Должны ли вы сделать частную собственность?


19
private string mWhatever;

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = value;
    }
}

Я видел некоторых людей, которые делают свойства для каждого члена, частные или нет ... это имеет какой-то смысл? Я мог видеть, что это имеет смысл в 1% случаев, когда вы хотите контролировать доступ к члену внутри класса, содержащего его, потому что, если вы не используете свойства для каждого члена, это приведет к несоответствиям и проверке, если член имеет доступ или нет (так как у вас есть доступ к обоим в области видимости класса).

Ответы:


17

Краткий ответ: да , когда есть необходимость. В противном случае используйте метод получения и реализации автоматически внедряемого свойства, напримерprivate string Whatever { get; set;}

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

Вот полное описание того, когда вы будете использовать частные сеттеры: Использование свойства C # .


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

4
Что такое подход близких доменов ?
Trisped

1
Я имел в виду частного сеттера в свойстве класса. Это должно предотвратить прямой доступ к заданному значению объекта и облегчить некоторую логическую проверку перед установкой значения.
Юсубов

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

12

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

Я видел некоторых людей, которые делают свойства для каждого члена, частные или нет ... это имеет какой-то смысл?

Я думаю, что это редко необходимо заранее, для каждого члена . Начать с

 private string Whatever;

Когда вы позже придете к точке, где вам потребуется инкапсуляция или условная точка останова для этого конкретного члена, вы все равно можете заменить его свойством с тем же именем - в большинстве случаев без изменения используемого кода Whatever. Но будьте осторожны, есть тонкие различия, см. Ответ Брайана Расмуссена в этом SO сообщении (ссылка также дана Эммадом Каримом, +1).


+1, также вы правы, в большинстве ответов пропущены исходные вопросы, мы типичные ИТ-парни :)
NoChance

Рефакторинг поля в собственность после-факта является кошмаром; требуя от вас перекомпилировать всех потребителей. Изменение автоматического свойства, чтобы он содержал пользовательскую логику, является легким. Если есть даже небольшой шанс увидеть код рефакторинга, будет гораздо меньше работы, если вы просто используете свойства с самого начала.
Дан

@Dan: в большинстве проектов, которые я видел, усилия практически одинаковы, вам придется перекомпилировать в обоих случаях. Тем не менее, я думаю, что вы правы, что использование свойств, особенно автоматических свойств, может помочь избежать некоторых тонких проблем с отражением или использованием переменных-членов в параметрах «out».
Док Браун

@DocBrown В любом случае, это определенно не всеобъемлющее утверждение. Есть много причин, чтобы просто держать это и использовать поле. Если вы можете предсказать рефакторинг, хотя, даже тонкие проблемы стоит рассмотреть.
Дан

7

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

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

С помощью свойства вы можете установить точку останова в установщике . В сочетании с условием, он может быть зафиксирован за один проход.

VC ++ имеет точки останова данных , но он доступен только для неуправляемого кода.


1

Если вы не используете свойство, ваш единственный вариант - использовать поле для хранения переменных данных. Свойства и поля имеют существенные различия. Большинство из этих различий встречаются как поля и свойства . Я предлагаю вам изучить различия, а затем сделать свой выбор в соответствии с потребностями вашего приложения. Однако имейте в виду, что использование полей вместо свойств не является обычной практикой ОО из-за их характера и недостатков.


1

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


Однако приведенный пример плохой. Подобные методы получения и установки свойств Boilerplate почти всегда являются плохой идеей. Если вы используете C # 3.0 или более позднюю версию, тогда гораздо лучше использовать свойства auto :

private string Whatever { get; set; };

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

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


На самом деле, я всегда думал, что это позор, что у вас не может быть свойства только для чтения, чтобы обеспечить возможность только записи значения в конструкторе (я предпочитаю неизменяемые типы ), но это было добавлено в C # 6.0 как «Инициализаторы авто-свойства», что позволяет делать:

private string Whatever { get; } = ...;

или

private string Whatever { get; };

вместе с

    Whatever = ...;

в конструкторе.


0

Это не обязательно делать это для частных свойств, но оно позволяет изменить способ, которым свойство получает / устанавливает базовое значение без изменения способа доступа к нему.

Например, изменение способа установки базового значения:

private string Whatever
{
    get
    {
        return this.mWhatever;
    }
    set
    {
        this.mWhatever = string.IsNullOrEmpty(value) ? string.Empty : value;
    }
}

0

Да

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

private List<User> users;
private List<User> Users
{
    get
    {
        if(users == null) users = new UserManager().GetUsers();
        return users;
    }
}

Теперь в других местах внутри моего класса я использую Usersсвойство вместо usersполя.

Другая возможная ситуация может возникнуть, когда вы хотите реализовать некоторую логику в поле, но централизованно в классе. Таким образом, вы можете создать GetFoo()метод или Fooсвойство для fooполя.

private string foo;
private string Foo
{
    get
    {
        return "Mr. " + foo;
    }
}

0

Что-то еще, чтобы рассмотреть:

Фактические свойства - это деталь реализации. Одна из целей ООП состоит в том, чтобы попытаться минимизировать раскрытие деталей реализации, где это практически возможно.

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

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

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


0

Я знаю, что это старый вопрос, и все, что сказал @Yusubov, правильно, но в отношении его второго пункта о конкретной логике в установщике, и, поскольку я не видел, чтобы кто-то конкретно упомянул об этом, идеальным примером будет, когда ваш класс реализует INotifyPropertyChangedинтерфейс.

Это используется тонна в WCF и Silverlight, которая позволяет вам знать, когда конкретное свойство изменилось с помощью логики в его установщике, как в классе ниже:

public class Settings : INotifyPropertyChanged
{
    public Settings() 
    { 
        this.CountryField = String.Empty; 
    }

    private string CountryField;
    public string Country
    {
        get { return this.CountryField; }
        set
        {
            if (Object.ReferenceEquals(this.CountryField, value)) { return; }

            this.CountryField = value;
            this.RaisePropertyChanged("Country");
        } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;

        if (propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.