Есть ли причины использовать частные свойства В C#?
Я только что понял, что C# собственность построить может также использоваться с частная модификатор доступа:
private string Password { get; set; }
хотя это технически интересно, я не могу себе представить, когда я буду использовать его с частное поле предполагает даже меньше церемониться:
private string _password;
и я не могу себе представить, когда я когда-нибудь должен быть в состоянии внутренне get а не set или set а не get закрытое поле:
private string Password { get; }
или
private string Password { set; }
но, возможно, есть вариант использования с вложенные / наследуемые классы или, возможно, где get / set может содержать логика вместо того, чтобы просто возвращать значение свойства, хотя я бы стремился сохранить свойства строго простыми и позволить явным методам делать любую логику, например GetEncodedPassword()
.
кто-нибудь использовать частные свойства В C# по какой-либо причине или это просто одна из тех технически возможных, но редко используемых конструкций в реальном коде?
дополнительное соглашение
хорошие ответы, читая их, я отбирал эти виды использования для частных свойств:
- когда частные поля должны быть лениво загружен
- когда частные поля нуждаются в дополнительной логике или вычисляются значения
- так как частные поля могут быть трудно отладка
- для того, чтобы"представить себе контракт"
- для внутреннего преобразования / упрощения открытого свойства в рамках сериализации
- обертывание глобальных переменных, которые будут использоваться внутри вашего класса
14 ответов:
Я использую их, если мне нужно кэшировать значение и хотите лениво загрузить его.
private string _password; private string Password { get { if (_password == null) { _password = CallExpensiveOperation(); } return _password; } }
основное использование этого в моем коде-это ленивая инициализация, как упоминали другие.
еще одна причина для частных свойств над полями заключается в том, что частные свойства намного проще отлаживать, чем частные поля. Я часто хочу знать такие вещи, как " это поле неожиданно устанавливается; кто первый вызывающий, который устанавливает это поле?"и это намного проще, если вы можете просто поставить точку останова на сеттере и нажать go. Вы можете поместить туда вход в систему. Вы можете положить показатели производительности там. Вы можете ввести проверки согласованности, которые выполняются в отладочной сборке.
в основном, это сводится к : код является гораздо более мощным, чем данные. Любой метод, который позволяет мне написать код, который мне нужен, является хорошим. Поля не позволяют вам писать код в них, свойства.
возможно, есть вариант использования с вложенными / унаследованными классами или, возможно, где get/set может содержать логику вместо того, чтобы просто возвращать значение свойства
Я лично использую это, даже если мне не нужна логика на геттер или сеттер свойства. Использование свойства, даже частного, помогает в будущем защитить ваш код, чтобы вы могли добавить логику в геттер позже, если это необходимо.
Если я чувствую, что свойство может в конечном итоге потребовать дополнительная логика, я иногда оберну его в частную собственность вместо использования поля, просто чтобы мне не пришлось менять свой код позже.
в полу-связанном случае (хотя и отличном от вашего вопроса), я очень часто использую частные сеттеры в публичных свойствах:
public string Password { get; private set; }
это дает вам публичный геттер, но сохраняет сеттер частным.
ленивая инициализация-это одно место, где они могут быть аккуратным, например,
private Lazy<MyType> mytype = new Lazy<MyType>(/* expensive factory function */); private MyType MyType { get { return this.mytype.Value; } } // In C#6, you replace the last line with: private MyType MyType => myType.Value;
тогда вы можете написать:
this.MyType
везде, а неthis.mytype.Value
и инкапсулируйте тот факт, что он лениво создается в одном месте.одна вещь, которая является позором, заключается в том, что C# не поддерживает определение области резервного поля для свойства (т. е. объявление его внутри определения свойства), чтобы полностью скрыть его и гарантировать, что он может быть доступен только через свойство.
одно хорошее использование для частных свойств get only-это вычисленные значения. Несколько раз у меня были свойства, которые являются частными только для чтения и просто делают расчет над другими полями в моем типе. Это не достойно метода и не интересно другим классам, поэтому это частная собственность.
единственное использование, которое я могу придумать
private bool IsPasswordSet { get { return !String.IsNullOrEmpty(_password); } }
свойства и поля не один в один. Свойство - это интерфейс класса (независимо от того, идет ли речь о его публичном или внутреннем интерфейсе), а поле-О реализации класса. Свойства не должны рассматриваться как способ просто открыть поля, они должны рассматриваться как способ раскрыть намерение и цель класса.
Так же, как вы используете свойства для представления контракта своим потребителям о том, что составляет ваш класс, вы также можете представить контракт себе по очень похожим причинам. Так что да, я использую частные свойства, когда это имеет смысл. Иногда частное свойство может скрывать детали реализации, такие как ленивая загрузка, тот факт, что свойство действительно является конгломератом нескольких полей и аспектов, или что свойство должно быть фактически создано с каждым вызовом (think
DateTime.Now
). Есть определенно моменты, когда имеет смысл применять это даже на себе в бэкэнде класса.
Я использую их в сериализации, с такими вещами, как
DataContractSerializer
или protobuf-net, которые поддерживают это использование (XmlSerializer
нет). Это полезно, если вам нужно упростить объект в рамках сериализации:public SomeComplexType SomeProp { get;set;} [DataMember(Order=1)] private int SomePropProxy { get { return SomeProp.ToInt32(); } set { SomeProp = SomeComplexType.FromInt32(value); } }
одна вещь, которую я делаю все время, это хранить" глобальные " переменные / кэш в
HttpContext.Current
private static string SomeValue{ get{ if(HttpContext.Current.Items["MyClass:SomeValue"]==null){ HttpContext.Current.Items["MyClass:SomeValue"]=""; } return HttpContext.Current.Items["MyClass:SomeValue"]; } set{ HttpContext.Current.Items["MyClass:SomeValue"]=value; } }
Я использую их время от времени. Они могут облегчить отладку вещей, когда вы можете легко поместить точку останова в свойство или добавить оператор ведения журнала и т. д.
может быть также полезно, если вам позже нужно каким-то образом изменить тип ваших данных или если вам нужно использовать отражение.
Я использую частные свойства, чтобы уменьшить код для доступа к вложенным свойствам, которые часто используются.
private double MonitorResolution { get { return this.Computer.Accesories.Monitor.Settings.Resolution; } }
это полезно, если есть много дополнительных свойств.
Это обычная практика, чтобы изменить только члены с get/set методы, даже частных. Теперь логика этого заключается в том, что вы знаете, что ваш get/set всегда ведет себя определенным образом (например, запуск событий), что, похоже, не имеет смысла, поскольку они не будут включены в схему свойств... но старые привычки умирают с трудом.
Это имеет смысл, когда есть логика, связанная с набором свойств или get (думаю, ленивая инициализация), и свойство используется в нескольких местах в классе.
Если это просто прямое резервное поле? Ничто не приходит на ум как хорошая причина.
Ну, как никто не упоминал, вы можете использовать его для проверки данных или блокировки переменных.
проверка
string _password; string Password { get { return _password; } set { // Validation logic. if (value.Length < 8) { throw new Exception("Password too short!"); } _password = value; } }
замок
object _lock = new object(); object _lockedReference; object LockedReference { get { lock (_lock) { return _lockedReference; } } set { lock (_lock) { _lockedReference = value; } } }
Примечание: при блокировке ссылки вы не блокируете доступ к элементам объекта ссылки.
ленивая ссылка: при ленивой загрузке вам может потребоваться сделать это асинхронно, для чего в настоящее время есть это AsyncLazy. Если вы находитесь на более старых версиях, чем Visual Studio SDK 2015 или не используете его, вы также можете использовать AsyncEx по AsyncLazy.