Різниця між властивістю та полем у C # 3.0+


140

Я усвідомлюю, що це, здається, є дублікатом Яка різниця між полем і властивістю в C #? але моє запитання має незначну різницю (з моєї точки зору):

Колись я це знаю

  • Я не буду використовувати свій клас із "техніками, які працюють лише на властивості" та
  • Я не буду використовувати код перевірки в getter / setter.

Чи є якась різниця (крім стилів / майбутніх розробок), як-от якийсь тип управління в налаштуванні властивості?

Чи є додаткова різниця між:

public string MyString { get; set; }

і

public string myString;

(Мені відомо, що для першої версії потрібен C # 3.0 або вище і що компілятор створює приватні поля.)


Відповіді:


117

Інкапсуляція.

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

Плюс вони з’являються по-різному в Intellisense :)

Редагувати: Оновлення питання щодо оновлених ОП - якщо ви хочете ігнорувати інші пропозиції тут, інша причина полягає в тому, що це просто непоганий дизайн OO. І якщо у вас не дуже вагома причина для цього, завжди вибирайте властивість над загальнодоступною змінною / полем.


9
Чому буде легше? Що заважає мені перетворити поле у ​​власність та додати приватне резервне поле? Як це впливає на код виклику?
Серж Вотьє

30
@Serge - це впливає на вже складений код. Наприклад, якщо ви розробляєте бібліотеку, яка використовується декількома додатками, для зміни поля на властивість у цій бібліотеці знадобиться перекомпіляція кожної програми. Якщо це була власність, ви можете оновити ресурс без побоювань.
Дастін Кемпбелл

Я повністю з вами згоден, я завжди використовую властивості. Мені просто цікаво можлива різниця
p4bl0

24
Якщо споживаючий код завжди перекомпілюється одночасно з класом, що впливає на нього (тому все приватне чи внутрішнє, без видимих ​​внутрішніх даних, є на 100% безпечним), то зробити його полем цілком нормально
ShuggyCoUk

1
вау Shuggy ваш коментар - це саме та відповідь, яку я шукав!
p4bl0

160

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

Ось перелік відмінностей:

  • Поля можуть використовуватися як вхід до out/refаргументів. Властивості не можуть.
  • Поле завжди дасть однаковий результат при виклику декількох разів (якщо ми залишаємо проблеми з декількома потоками). Властивість, така як DateTime.Nowне завжди, сама по собі дорівнює.
  • Властивості можуть кидати винятки - поля ніколи цього не роблять.
  • Властивості можуть мати побічні ефекти або зайняти дуже довго часу. Поля не має побічних ефектів і завжди буде настільки швидко, наскільки можна очікувати для даного типу.
  • Властивості підтримують різну доступність для getters / setters - поля не мають (але поля можна зробити readonly )
  • При використанні відображення властивості та поля трактуються як різні, MemberTypesтому вони розташовані по-різному ( GetFieldsvsGetProperties , наприклад)
  • Компілятор JIT може трактувати доступ до властивостей дуже по-різному в порівнянні з полем доступу. Однак він може компілювати до ідентичного нативного коду, але можливість для різниці є.

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

15
@Noldorin: Я згоден, але, на жаль, тут має бути ключове слово. З полями така поведінка гарантована. Я не кажу, що ви повинні використовувати поля, але важливо усвідомлювати смислові відмінності.
Брайан Расмуссен

4
Так, досить справедливо. Програмісти-початківці не мають поняття про ці речі часто, на жаль ...
Noldorin

2
Також поля можуть мати ініціалізатор поля, тоді як властивості повинні бути ініціалізовані в конструкторі.
Dio F

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

41

Пара швидких, очевидних відмінностей

  1. Властивість може мати ключові слова доступу.

    public string MyString { get; private set; }
  2. Власність може бути замінена нащадками.

    public virtual string MyString { get; protected set; }

1
mmh .. nr 2 цікаво .. я не думав про це
p4bl0

14

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


11

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

Властивості беруть участь в інтерфейсних класах. Наприклад:

interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
}

Цей інтерфейс можна задовольнити кількома способами. Наприклад:

class Person: IPerson
{
    private string _name;
    public string FirstName
    {
        get
        {
            return _name ?? string.Empty;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException("value");
            _name = value;
        }
    }
    ...
}

У цій реалізації ми захищаємо як Personклас від потрапляння в недійсний стан, так і абонента від виведення нуля з непризначеного властивості.

Але ми могли б підштовхнути дизайн ще далі. Наприклад, інтерфейс може не мати справу з сеттером. Цілком законно сказати, що споживачі IPersonінтерфейсу зацікавлені лише в тому, щоб отримати майно, а не встановлювати його:

interface IPerson
{
    string FirstName { get; }
    string LastName { get; }
}

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

class PersonBuilder: IPersonBuilder
{
    IPerson BuildPerson(IContext context)
    {

        Person person = new Person();

        person.FirstName = context.GetFirstName();
        person.LastName = context.GetLastName();

        return person;

    }
}

...

void Consumer(IPersonBuilder builder, IContext context)
{
    IPerson person = builder.BuildPerson(context);
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

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

Інша цілком реальна реалізація IPersonбуде незмінним класом людини та відповідною фабрикою персоналу:

class Person: IPerson
{
    public Person(string firstName, string lastName)
    {

        if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName))
            throw new System.ArgumentException();

        this.FirstName = firstName;
        this.LastName = lastName;

    }

    public string FirstName { get; private set; }

    public string LastName { get; private set; }

}

...

class PersonFactory: IPersonFactory
{
    public IPerson CreatePerson(string firstName, string lastName)
    {
        return new Person(firstName, lastName);
    }
}
...
void Consumer(IPersonFactory factory)
{
    IPerson person = factory.CreatePerson("John", "Doe");
    Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}

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


7

Перший:

public string MyString {get; set; }

є власністю; другий ( public string MyString) позначає поле.

Різниця полягає в тому, що певні методи (прив'язка даних ASP.NET для екземплярів) працюють лише на властивостях, а не на полях. Те саме стосується XML-серіалізації: серіалізуються лише властивості, поля не серіалізуються.


8
Неправильно. XML-серіалізація НЕ серіалізує публічні поля.
Серж Вотьє

2
Може бути. Але коли ви створюєте об’єкт даних Джерело даних з класу, ви можете використовувати лише властивості, а не поля. (Якщо я не зробив щось не так: P)
Свиш

Добре - ДУХИ;), але я ще раз пишу, мені подобається сильна роль властивості в мові C #. Значно краще реалізовано, ніж у Java (отже, з самого початку) Багато, можливо, всі .net рішення працюють лише на властивості. WPF, ASPX та багато іншого.
Jacek Cz

3

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

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

Подумайте про властивості як синтаксичний цукор для функцій getXXX () / setXXX (). Ось як вони реалізуються за лаштунками.


1

Є ще одна важлива різниця між полями та властивостями.

Під час використання WPF ви можете пов'язувати лише загальнодоступні властивості. Прив’язування до публічного поля не вийде . Це справедливо навіть тоді, коли вони не реалізуються INotifyPropertyChanged(хоча ви завжди повинні).


Добре - ДУХИ;), але я ще раз пишу, мені подобається сильна роль властивості в мові C #. Значно краще реалізовано, ніж у Java (отже, з самого початку) Багато, можливо, всі .net рішення працюють лише на властивості. WPF, ASPX та багато іншого.
Jacek Cz

1

Серед інших відповідей та прикладів, я вважаю, що цей приклад корисний у деяких ситуаціях.

Наприклад, скажімо, у вас є таке:OnChange property

public Action OnChange { get; set; }

Якщо ви хочете , щоб делегати використання , ніж вам необхідно змінити його , OnChangeщоб fieldце подобається:

public event Action OnChange = delegate {};

У такій ситуації ми захищаємо своє поле від небажаного доступу чи модифікації.


0

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


"завжди" - це лійт до важкого слова. У C # (краще, ніж у Java) властивість має сильне положення, є (ймовірно, без винятку) основним / методом "прив'язки" в ASP, WPF та інших. Але все-таки я можу уявити, що дизайн з полем, що не має власності, не має сенсу (іноді)
Jacek Cz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.