2010-02-12 14 views
34

Czytałem w wielu miejscach, że publiczne eksponowanie pól nie jest dobrym pomysłem, ponieważ jeśli później chcesz zmienić właściwości, będziesz musiał przekompilować cały kod, który używa twojej klasy.C#, niezmienność i publiczne pola tylko do odczytu

Jednak w przypadku klas niezmiennych, nie widzę powodu, dla którego kiedykolwiek musiałbyś zmienić właściwości - w końcu nie zamierzasz dodawać logiki do "zestawu".

Jakieś przemyślenia na ten temat, czy czegoś brakuje?

Przykład różnicy, dla tych, którzy łatwiej odczytać kodu niż tekst :)

//Immutable Tuple using public readonly fields 
public class Tuple<T1,T2> 
{ 
    public readonly T1 Item1; 
    public readonly T2 Item2; 
    public Tuple(T1 item1, T2 item2) 
    { 
     Item1 = item1; 
     Item2 = item2; 
    } 
} 

//Immutable Tuple using public properties and private readonly fields 
public class Tuple<T1,T2> 
{ 
    private readonly T1 _Item1; 
    private readonly T2 _Item2; 
    public Tuple(T1 item1, T2 item2) 
    { 
     _Item1 = item1; 
     _Item2 = item2; 
    } 
    public T1 Item1 { get { return _Item1; } } 
    public T2 Item2 { get { return _Item2; } } 
} 

Oczywiście, można korzystać z funkcji automatycznego właściwości (public T1 Item1 { get; private set; }), ale to tylko dostaje „zgodził niezmienność” jako w przeciwieństwie do "gwarantowanej niezmienności" ...

Odpowiedz

11

Jest to oczywiste przeoczenie z własności, że nie można napisać coś takiego:

public T2 Item2 { get; readonly set; } 

Nie jestem nawet pewien readonly jest najlepsze słowo aby korzystać oznaczać „można ustawić tylko w konstruktorze”, ale to właśnie utknęliśmy.

To jest właściwie funkcja, o którą prosiło wiele osób, więc miejmy nadzieję, że wkrótce zostanie wprowadzona w hipotetycznej nowej wersji C#.

Zobacz this related question.

+2

Hm, jest „hipotetyczna nowa wersja C#” Myślę, że wiem, kto jest blogiem, którego czytasz;) – Benjol

+1

Tak, rozważamy to. Hipotetycznie. Jest to raczej trudniejszy problem, niż się wydaje na pierwszy rzut oka. –

+2

@Eric Lippert, teraz tylko się z nami drażnisz. Oczekuję wkrótce postu o trudnościach :) – Benjol

0

W standardowym postępowaniu śledzę twój drugi przykład tylko używając "tylko do odczytu", gdy obiekt jest publiczny lub narażony na ataki na nieumyślne manipulowanie. Używam modelu "uzgodnionej niezmienności" w bieżącym projekcie budującym framework wtyczek. Oczywiście, przy ustalonej niezmienności, ochrona readonly jest usuwana.

Tylko w rzadkich przypadkach wystawiam pole - publiczne, wewnętrzne lub inne. Po prostu nie czuje się dobrze, chyba że pisanie własności {get;} zajmuje więcej czasu, niż jestem skłonny dać.

0

Ideą właściwości jest to, że nawet jeśli nie masz zamiaru zmieniać ich teraz lub później, może zajdziesz potrzeba w jakiś nieprzewidziany sposób. Powiedzmy, że musisz zmienić getter, aby wykonać jakieś obliczenia lub rejestrację. Może potrzebujesz dodać obsługę wyjątku. Wiele potencjalnych powodów.

Należy również rozważyć semantykę. jeśli T1 jest typem wartości, a nie typem odniesienia, wówczas dostęp do obiektu obj.Item1 zwraca kopię elementu _Item1 w programie pobierającym, podczas gdy uzyskanie dostępu do elementu Pozycja 1 bez elementu pobierającego nie spowoduje pobrania kopii. Oznacza to, że podczas gdy Element 1 może być wewnętrznie niezmienny, obiekt typu zwróconej wartości nie jest. Nie mogę wymyślić powodu, dla którego byłoby to dobre,, ale to jest różnica.

+0

Co to jest o kopiowaniu po powrocie za pośrednictwem nieruchomości? Czy masz na to referencję? – Benjol

+0

Typy wartości należy kopiować po ich minięciu. Tak działa C#. –

+1

Tak, ale dlaczego pole nie skopiowano również przy przejściu? Nie widzę, gdzie to byłby problem. – Benjol

3

Może nie być konieczne dodawanie jakiejkolwiek logiki do setera w przyszłości, ale może być konieczne dodanie logiki do pobierającej.

To wystarczający wystarczający powód, by używać właściwości zamiast eksponować pola.

Jeśli czuję się bardzo rygorystycznie, to wybieram pełną niezmienność (wyraźne readonly pola z odsłoniętymi getterami i bez ustawiaczy).Jeśli czuję się leniwy, prawdopodobnie wybrałbym "uzgodnioną niezmienność" (auto-właściwości z odsłoniętymi getterami i ustawieniami prywatnymi).

11

C# 6.0 obsługuje teraz inicjalizatory automatycznej właściwości.

Autodopasowanie właściwości automatycznej umożliwia przypisanie właściwości bezpośrednio w obrębie ich deklaracji. W przypadku właściwości tylko do odczytu, zajmuje się ona całą ceremonią wymaganą do zapewnienia, że ​​nieruchomość jest niezmienna.

można zainicjować tylko do odczytu właściwości w konstruktorze lub przy użyciu automatycznego inicjowania

public class Customer 
{ 
    public Customer3(string firstName, string lastName) 
    { 
     FirstName = firstName; 
     LastName = lastName; 
    } 
    public string FirstName { get; } 
    public string LastName { get; } 
    public string Company { get; } = "Microsoft"; 
} 

var customer = new Customer("Bill", "Gates"); 

można przeczytać więcej o inicjalizatorów auto własności here