Загальнодоступні поля та автоматичні властивості


353

Нам часто говорять, що ми повинні захищати інкапсуляцію шляхом створення методів getter та setter (властивості в C #) для класових полів, а не піддавати дії поля зовнішнього світу.

Але буває багато разів, коли поле є просто там, щоб утримувати значення і не вимагає жодних обчислень для отримання чи встановлення. Для цього ми всі зробили б це число:

public class Book
{
    private string _title;

    public string Title
    {
          get{ return _title;  }
          set{ _title = value; }
    }
}

Ну, у мене є зізнання, я не міг терпіти все це (насправді, писати це не довелося, треба було дивитись на нього), тому я пішов ізгоєм і використовував публічні поля.

Потім йде C # 3.0, і я бачу, що вони додали автоматичні властивості:

public class Book
{
    public string Title {get; set;} 
}

що охайніше, і я вдячний за це, але насправді, що таке інше, ніж просто зробити публічне поле?

public class Book
{
    public string Title;
}


6
Я перетворив фельд у власність просто для того, щоб я міг встановити точку розриву на
сеттера

1
Я схильний до того, щоб зробити все, що не є приватною власністю, оскільки розуміння, що я повинен переробляти поле у ​​власність, призвело до непотрібного головного болю. Властивості, поля та методи. О мій! викликає несумісність, яка мене вкусила в минулому.
Стівен Векслер

2
propФрагмент коду дозволяє швидко створювати властивості. Просто введіть propпотім вкладку.
Тоно Нам

Відповіді:


175

У спорідненому запитанні, яке у мене було певний час тому, у блозі Джеффа було посилання на публікацію, що пояснює деякі відмінності.

Властивості проти загальнодоступних змінних

  • Відображення працює по-різному на змінні та властивості, тому якщо ви покладаєтесь на рефлексію, простіше використовувати всі властивості.
  • Ви не можете зв’язати дані зі змінною.
  • Зміна змінної до властивості - це невід'ємна зміна. Наприклад:

    TryGetTitle(out book.Title); // requires a variable

24
"Зміна змінної до властивості - це невід'ємна зміна." Це, звичайно, стосується лише написання бібліотеки для багаторазового використання, чим не займаються більшість розробників .
Стівен

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

28
Також поле є змінною і може передаватися посиланням ( refабо outключовим словом), тоді як властивість є парою аксесуарів і не може передаватися посиланням. Наприклад, bool success = TryGetMyTitle(out myBook.Title);які використання outбудуть працювати з полем, а не працювати з властивістю. Це чіткий приклад того, чому перехід від поля до власності є переломною зміною!
Джеппе Стіг Нільсен

2
@KyleBaran Ні, це не має особливого сенсу, оскільки властивість - це пара методів аксесуара, а не змінна. Звичайне, що потрібно зробити - це оголосити локальну змінну (можливо, прочитати властивість, перенести її значення в локальну змінну), передати локальну змінну як ref/ out, а потім встановити властивість на значення, яке має місцева змінна. Але тоді названий метод не має доступу до властивості, він отримує доступ до локальної змінної, яку ви там зробили.
Джеппе Стіг Нільсен

5
@theberserker Щоправда, хоча в C # 6 ви можете зробити це, public int Foo { get; }яке створить автоматичну властивість із полем лише для читання резервного копіювання.
Майкл Стум

83

Ігноруючи проблеми з API, я вважаю, що найцінніше використання ресурсу - це налагодження.

Налагоджувач CLR не підтримує точки перерви даних (це робить більшість нативних налагоджувачів). Отже, встановити точку перерви на читанні чи записі певного поля на класі неможливо. Це дуже обмежує в певних сценаріях налагодження.

Оскільки властивості реалізовані як дуже тонкі методи, можна встановити точки перерви на читання та запис їх значень. Це дає їм велику ногу над полями.


2
Через десять років тут є точки
пропуску

72

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

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


9
Мені сподобалась ця відповідь, оскільки в ній не використовуються слова "відображення", "інтерфейс" або "переосмислення". (занадто погано щодо 'контракту')

65

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


1
Я б сказав, що якщо вам потрібен інтерфейс, який визначає властивості, це повинен бути абстрактний клас. Тільки тому, що c # дозволяє визначати властивості в інтерфейсах, не означає, що ви повинні їх використовувати. Це поганий дизайн.
Одіс

8
@odyodyodys - я не впевнений, що згоден, що це поганий дизайн. Поясніть, будь ласка, своє обґрунтування?
Заїд Масуд

4
@odyodyodys Я згоден з zooone9243: Imp, з точки зору дизайну, немає різниці між декларуванням властивості та оголошенням пари getter / setter (що є звичайною практикою для інтерфейсів).
MartinStettner

22
@ zooone9243, + MartinStettner: Це було 6 місяців тому, з того часу я багато чому навчився. Я беру його назад :)
Одіс

47

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


10

Вся справа в версіях та стабільності API. Немає різниці у версії 1 - але пізніше, якщо ви вирішите, що вам потрібно зробити це властивістю з певним видом перевірки помилок у версії 2, вам не доведеться міняти свій API - жодних змін коду ніде, крім визначення майна.


10

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


8

Немає нічого поганого в тому, щоб зробити поле public. Але пам’ятайте, що створювати за getter/setterдопомогою privateполів - це не капсулювання. ІМО. Якщо вам не байдужі інші функції а Property, ви також можете зробити це public.


1

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

Якщо ви будете мати лише публічний атрибут, тоді у вас буде менша гнучкість.

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


0

Одне, що я вважаю дуже корисним, а також усі коди та причини тестування, це те, що якщо це властивість проти поля, це те, що Visual Studio IDE показує вам посилання на властивість, але не на поле.


0

Мій pov після цього робив деякі дослідження

  1. Перевірка.
  2. Дозволити змінити доступ поведінки властивості дозволу, що змінюється.
  3. Мета налагодження Ми зможемо дізнатися, коли і що змінюється властивість, встановивши точку розриву в аксесуарі.
  4. У нас може бути лише полевий набір. Наприклад, public set () і private get (). З громадським полем це неможливо.

Це дійсно дає нам більше можливостей та розширюваності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.