Чи варто робити приватну власність?


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
Я мав на увазі приватного сетера у властивості класу. Він повинен перешкоджати прямому доступу до встановленого значення з об'єкта та полегшувати певну логічну перевірку перед встановленням значення.
Юсубов

наявність приватних змінних із загальнодоступними сеттерами / getters (навіть якщо вони просто наївні) також має перевагу в тому, що якщо ваш код буде зібраний у бібліотеку, підпис залишиться незмінним, якщо ви заміните свого наївного сеттера / getters на ті, які мають сторону- ефект тощо, але якщо ви використовуєте просту загальну змінну замість цього, підпис бібліотеки буде змінено, якщо ви змінили її на приватний w / не наївний сетер / getters. .. це означає, що якщо ваша бібліотека змінилася таким чином, то споживачам вашої бібліотеки потрібно було б перекомпілювати.
orion elenzil

12

Тут вже є кілька хороших відповідей, але я думаю, що більшість із них пропускає один пункт вашого запитання:

Я бачив деяких людей, які створюють властивості для кожного члена, приватного чи ні ... це має сенс?

Я думаю, що це рідко необхідно заздалегідь, для кожного члена . Починати з

 private string Whatever;

Коли пізніше ви перейдете до точки, коли для цього конкретного члена вам потрібна інкапсуляція або умовна точка розриву, ви все одно можете замінити його властивістю з тим самим іменем - у більшості випадків без зміни коду, який використовує Whatever. Але будьте обережні, є тонкі розбіжності, дивіться відповідь Брайана Расмуссена в цьому дописі SO (посилання також дане Еммадом Каремом, +1).


+1, також ви правильні, більшість відповідей пропустили оригінальні питання, ми типові ІТ-хлопці :)
NoChance

Повторне відновлення поля до власності після факту - це кошмар; вимагаючи від вас перекомпілювати всіх споживачів. Зміна автоматичної властивості, щоб містити власну логіку, є легким вітром. Якщо є навіть невеликий шанс побачити код рефактора, це буде набагато менше роботи, якщо ви просто використовуєте властивості з самого початку.
Dan

@Dan: У більшості проектів я бачив зусилля зовсім однакові, вам доведеться перекомпілювати в обох випадках. Тим не менш, я вважаю, що ви правильні, що використання властивостей, особливо авто властивостей, може допомогти уникнути деяких субтильних проблем з відображенням або використанням змінних членів у "вихідних" параметрах.
Док Браун

@DocBrown У будь-якому випадку, це точно не загальна заява. Є багато причин, щоб просто зробити це просто і використовувати поле. Якщо ви можете спрогнозувати рефактор, то варто навіть розглянути навіть найтонші проблеми.
Dan

7

Однією з найбільших переваг такого підходу є те, що ви отримуєте контроль над зміною змінних .

Розглянемо наступне.
Ви налагоджуєте великий проект. Певний метод кидає виняток. Ви встановлюєте точку перерви і виявляєте, що певна змінна члена має неправильне значення. Скажімо, ваш код дуже широко покладається на цю змінну, і ви знайдете сотні звичок написання ( сценарій спагетті ). Таким чином, ви не можете зрозуміти, який із цих звичаїв присвоїв погане значення.
Якщо код багатопотоковий, налагодження може стати справжнім кошмаром.

Маючи властивість, ви можете встановити точку розриву в сетері . У поєднанні з умовою він може бути забитий за один пробіг.

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


1

Якщо ви не використовуєте властивість, ваш єдиний інший варіант - використовувати поле для зберігання змінних даних. Властивості та поля мають суттєві відмінності. Більшість цих відмінностей виявлено Поля проти Властивості . Я пропоную вам вивчити відмінності, а потім зробити вибір відповідно до потреб вашої програми. Однак майте на увазі, що використання полів замість властивостей не є звичайною практикою ОО через їх природу та недоліки.


1

Приватні властивості можуть бути дуже корисними для інкапсуляції поведінки речей, які є внутрішніми для вашого класу. Тільки тому, що вони приватні, не означає, що ви не повинні скористатися синтаксичним цукром, який надають вам властивості.


Наведений приклад, однак, поганий. Отримати властивості котлоагрегатів та подібні сетери майже завжди є поганою ідеєю. Якщо ви використовуєте C # 3.0 або новішу версію, автоматичні властивості версію - це набагато краща ідея:

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.