C#, неизменность и общедоступные поля только для чтения

Я читал во многих местах, что поля представления публично не являются хорошей идеей, потому что, если Вы позже хотите измениться на свойства, необходимо будет перекомпилировать весь код, который использует класс.

Однако в случае неизменных классов, я не вижу, почему необходимо было бы когда-либо изменяться на свойства - Вы не собираетесь быть добавляющей логикой к 'набору', в конце концов.

Какие-либо мысли об этом, я пропускаю что-то?

Пример различия, для тех, кто прочитал код более легко, чем текст :)

//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; } } 
}

Конечно, Вы могли использовать автосвойства (public T1 Item1 { get; private set; }), но это только получает Вас 'согласованная неизменность' в противоположность 'гарантируемой неизменности'...

34
задан True Soft 26 July 2010 в 18:33
поделиться

4 ответа

Это очевидное упущение свойств, что вы не можете написать что-то вроде:

public T2 Item2 { get; readonly set; } 

Я даже не уверен, что readonly - лучшее слово, которое можно использовать для обозначения "может быть установлено только в конструкторе", но это то, с чем мы застряли.

На самом деле это функция, о которой просили многие люди, поэтому будем надеяться, что она будет введена в гипотетическую новую версию C# в ближайшее время.

См. этот связанный вопрос.

11
ответ дан 27 November 2019 в 17:14
поделиться

Возможно, вам не понадобится добавлять какую-либо логику в сеттер в будущем, но вы может потребоваться добавить логику в геттер .

Это достаточно веская причина для того, чтобы использовать свойства, а не раскрывать поля.

Если я чувствую себя строгим, я бы выбрал полную неизменяемость (явное только для чтения поддерживающие поля с открытыми геттерами и без сеттеров). Если мне лень, я, вероятно, выберу «согласованную неизменяемость» (автоматические свойства с открытыми геттерами и частными сеттерами).

4
ответ дан 27 November 2019 в 17:14
поделиться

В качестве стандартной практики я следую вашему второму примеру, используя 'readonly' только тогда, когда объект является публичным или уязвимым к непреднамеренному вмешательству. Я использую модель 'agreed immutability' в текущем проекте по созданию фреймворка плагинов. Очевидно, что при согласованной неизменяемости защита readonly снимается.

Только в редких случаях я раскрываю поле - публичное, внутреннее или иное. Это кажется неправильным, если написание свойства {get;} занимает больше времени, чем я готов отдать.

0
ответ дан 27 November 2019 в 17:14
поделиться

Идея свойств заключается в том, что даже если вы не собираетесь изменять их сейчас или позже, возможно, это может понадобиться каким-то непредвиденным образом. Допустим, вам нужно изменить getter для выполнения какого-либо вычисления или протоколирования. Может быть, вам нужно добавить обработку исключений. Множество потенциальных причин.

Также следует учитывать семантику. Если T1 - тип значения, а не тип ссылки, то обращение к obj.Item1 возвращает копию _Item1 в геттере, тогда как обращение к Item1 без геттера не приведет к получению копии. Это означает, что хотя Item1 может быть неизменяемым внутри, возвращаемый объект типа значения таковым не является. Я не могу придумать причину, по которой это было бы хорошо, но это разница.

0
ответ дан 27 November 2019 в 17:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: