Есть ли причины использовать частные свойства В 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 183

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.