Что лучше между модификатором readonly и частным сеттером? - PullRequest
53 голосов
/ 02 ноября 2011

Я работал над созданием класса, и вдруг мне пришла в голову мысль, в чем разница между двумя кодами:

public readonly string ProductLocation;

И

public string ProductLocation
{
     get;
     private set;
}

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

Ответы [ 5 ]

67 голосов
/ 02 ноября 2011

Первое поле доступно только для чтения, а второе компилируется как пара методов (и все чтения свойства ProductLocation компилируются в вызовы соответствующего метода get и записываются в него. скомпилированы в вызовы метода set; внутренне эти методы будут считывать / записывать во внутреннее автоматически генерируемое поле, не предназначенное только для чтения). Я бы сказал, что самое важное отличие - безопасность потоков ! (как? читай дальше!)

Основное использование класса будет выглядеть точно одинаково: код в других классах сможет только читать значение, но не изменять его. Кроме того, код для чтения значения будет выглядеть точно так же (например, print(myInstace.ProductLocation); здесь вы не можете сказать, как оно было объявлено, круто, а?)

Первое, самое тривиальное отличие состоит в том, что свойство с закрытым установщиком позволяет экземплярам одного класса изменять значение, в то время как в случае свойства только для чтения, даже сам объект не сможет изменить значение.

Теперь для обеспечения безопасности потоков. Атрибут readonly в поле изменит свою семантику видимости памяти при работе с несколькими потоками (так же, как поля final Java).

Поле readonly может быть назначено только при объявлении или в конструкторе. Значение, присвоенное полю readonly, не может быть изменено (по крайней мере, не нормальным способом), и гарантируется, что каждый поток увидит правильно инициализированное значение после того, как конструктор вернет . Следовательно, поле readonly по своей природе является поточно-ориентированным.

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

Таким образом, если значение представляет собой нечто, что семантически не может быть изменено после создания объекта, вам не следует объявлять частный установщик (это будет означать, что объект может его изменить). Перейдите к полю только для чтения (и, возможно, объявите его закрытым и объявите открытое свойство, доступ к которому имеет только получатель!) На самом деле это предпочтительная форма, поскольку выставлять поля нехорошо, лучше показывать только методы - там Есть много причин, объясняющих, почему в этот ответ )

21 голосов
/ 30 декабря 2016

С C # 6.0 инициализатором авто-свойств существует меньший шаблонный способ сделать

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 

То есть

public string ProductLocation { get; } 

Этотолько для чтения.Инициализируется только из конструктора или встроенного.Он не может быть отредактирован после инициализации.(Неизменный из любого места)

Однако, если вы используете закрытый набор;

public string ProductLocation { get; private set } 

Это доступно только для чтения извне.Но может быть инициализирован в любое время в любом месте внутри самого класса.И может быть отредактирован в пределах его жизненного цикла самим классом.(Изменяемый из класса, неизменный снаружи)

18 голосов
/ 02 ноября 2011

Как правило, в .NET не рекомендуется публично выставлять поля-члены, которые должны быть обернуты свойством. Итак, давайте предположим, что у вас может быть

private readonly string productLocation; 
public string ProductLocation { get { return productLocation; } } 

против

public string ProductLocation { get; private set; }

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

Во второй версии внешние потребители по-прежнему не имеют доступа к настройке значения. Однако сам класс может изменить значение в любое время. Если все, что у вас есть, это DTO (то есть класс, который только транспортирует данные, у него нет логики, выраженной через методы), то это, по сути, не так уж и отличается от версии readonly. Однако для классов с методами эти методы могут изменить значение, стоящее за ProductLocation.

Если вы хотите применить концепцию неизменяемого поля после постройки, используйте readonly. Но для DTO я мог бы пойти на опцию private set;, в основном потому, что это менее шаблонный код.

8 голосов
/ 02 ноября 2011

Первый (с использованием readonly) будет означать, что объект не может даже изменить значение своего собственного поля , если объект был создан, а другие никогда не смогут его изменить.

Второй (с использованием private set) будет означать, что объект может изменить значение своего поля после его создания, но другие никогда не смогут его изменить.

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

4 голосов
/ 02 ноября 2011

Первое поле , значение которого можно установить только при создании экземпляра .

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


Исправление: свойство может быть установлено в любое время любым экземпляром того же класса (и не толькосодержащий его объект).

...