Яка різниця між полем і властивістю?


1129

У C #, що робить поле відмінним від властивості, і коли слід використовувати поле замість властивості?


32
Microsoft безпосередньо відповідає на це питання (для всіх мов .NET) як частина своїх Правил дизайну членів . Детальніше див у статтях Дизайн власності та Дизайн поля . Зауважимо, існує різниця між членами екземпляра та статичними членами.
DavidRR

Відповіді:


979

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

public class MyClass
{
    // this is a field.  It is private to your class and stores the actual data.
    private string _myField;

    // this is a property. When accessed it uses the underlying field,
    // but only exposes the contract, which will not be affected by the underlying field
    public string MyProperty
    {
        get
        {
            return _myField;
        }
        set
        {
            _myField = value;
        }
    }

    // This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
    // used to generate a private field for you
    public int AnotherProperty{get;set;} 
}

@Kent вказує, що для інкапсуляції полів властивості не потрібно, вони можуть зробити розрахунок на інших полях або служити іншим цілям.

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


185
Варто зазначити, що для інкапсуляції полів властивості не потрібні. Поза полем власності не може бути поля. Це може бути обчислення або повернення постійної чи будь-якої іншої.
Кент Бугаарт

9
"не впливаючи на зовнішній спосіб, до них звертаються речі, які використовують ваш клас." вибачте, якщо я неправильно розумію, то, але чому взагалі необхідність модифікаторів доступу перед властивостями, якщо поле позаду, здається, справляється з цим? тобто навіщо робити власність чим-небудь, крім публічного?
Чаккі

18
Ваша відповідь була прямо перед правками та незвично внесеними невірними коментарями. Власність завжди повинна інкапсулювати одне або декілька полів і ніколи не повинна робити важких підйомів чи валідацій. Якщо вам потрібна властивість такого UserName або Password для перевірки, змініть їх тип із рядків на Value Objects . Існує невимовлений договір між класотворцем і споживачем. Поля утримує стан, Властивості виставляють стан за допомогою одного або декількох полів, Пустоти змінюють стан (важкий підйом), а Функції виконують запити (важкий підйом). Це не камінь, просто втрачають очікування.
Suamere

6
@jpaugh Якщо я споживач класу, я дотримуюся договорів, встановлених творцем класу. Якщо майно є string, мій контракт: присвоїти будь-які символи довжиною до ~ 2bil. Якщо власність є DateTime, мій договір такий: призначити будь-які номери в межах DateTime, які я можу шукати. Якщо творець додає обмеження для сетерів, ці обмеження не передаються. Але якщо натомість творець змінює тип з stringна Surname, то їх новий клас Прізвище передає обмеження, і властивість public Surname LastNameне має перевірки встановлення. Також Surnameє багаторазовим використання.
Suamere

4
А оскільки Surname, на моєму прикладі, багаторазове використання, вам не потрібно буде турбуватися про згодом копіювання / вставлення цих перевірок у програмі налаштування властивостей до інших місць коду. Не дивно, чи підтвердження Прізвища є в декількох місцях, якщо ви коли-небудь вносите зміни до бізнес-правил для Прізвищ. Ознайомтесь із посиланням, яке я опублікував про Value Objects
Suamere

261

Об'єктно-орієнтовані принципи програмування говорять про те, що внутрішня робота класу повинна бути прихованою від зовнішнього світу. Якщо ви відкриєте поле, ви, по суті, викриваєте внутрішню реалізацію класу. Тому ми обертаємо поля властивостями (або методами у випадку Java), щоб дати нам можливість змінювати реалізацію, не порушуючи код залежно від нас. Бачачи, як ми можемо розмістити логіку у властивості, також ми можемо виконувати логіку перевірки тощо, якщо вона потрібна. C # 3 має, можливо, заплутане поняття автоконтрастності. Це дозволяє нам просто визначити властивість, і компілятор C # 3 створить для нас приватне поле.

public class Person
{
   private string _name;

   public string Name
   {
      get
      {
         return _name;
      }
      set
      {
         _name = value;
      }
   }
   public int Age{get;set;} //AutoProperty generates private field for us
}

89
+1 для згадки про автопротези - я думаю, що це щось із багатьох відповідей тут (і в інших місцях) забули внести. Без цього пояснення все ще може бути досить важко зрозуміти, що public int myVar { get; set; }насправді стоїть (і я припускаю, що це причина принаймні 50% звернень, які отримує це питання).
Priidu Neemre

7
+1 також для згадування про авто та згадування про те, як він працює ("AutoProperty генерує для нас приватне поле") Це була відповідь, яку я шукав на питання, яке у мене виникло. Під час дослідження я не бачив на сторінці MSDN про них жодних ознак того, що було створено приватне поле і викликало плутанину. Я думаю, що це означає? "Атрибути дозволені на власне реалізованих властивостях, але, очевидно, не на полях резервного копіювання, оскільки вони недоступні у вихідному коді. Якщо вам потрібно використовувати атрибут у полі резервного копіювання властивості, просто створіть звичайну властивість." але не був впевнений.
Nyra

3
Зауважте, що наведений приклад не інкапсулює присідання. Ця властивість дає 100% повний доступ до приватного поля, тому це зовсім не орієнтоване на об’єкти. У цьому випадку ви також можете мати публічне поле. Зрозуміло, це допомагає (незначно) рефакторний код у майбутньому, але будь-яка IDE, яка стоїть за метл, може перетворити поле у ​​властивість за допомогою декількох натискань клавіш. Відповідь може бути технічно правильною щодо того, як працюють властивості, але це не дає хорошого "пояснення OOP" щодо їх використання.
сара

2
@kai Я погоджуюсь, що відповідь занадто спрощено і не показує всієї сили автомайна, проте я не погоджуюся, що це не орієнтоване на об’єкти. Ви можете перевірити різницю між полями та властивостями . Поля не можуть бути віртуальними, а virtualсамі по собі є частиною об'єктно-орієнтованого програмування.
Gobe

Зрозуміло, є деякі функціональні відмінності. Я б не закликав virtualOOP як такий. Це інструмент, що дозволяє поліморфізм, який є одним з ключових інструментів, який ВИМОГАЄ OOP. Однак це не є OOP сам по собі, і немає нічого притаманного OOP про публічну автовласність. Я б не зараховував такі речі, як відбиття чи пов'язані з використанням OOP дані. Зазвичай я б не був настільки педантичним щодо цього, але у відповіді конкретно згадуються принципи ОО як рушійної сили прикладу коду, і я не згоден з цим.
сара

164

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


98

Наведу кілька прикладів використання властивостей, які можуть призвести до повороту передач:

  • Ледача ініціалізація : Якщо у вас є властивість об'єкта, який дорого завантажувати, але до нього не доступно все так багато в звичайних прогонах коду, ви можете затримати його завантаження через властивість. Таким чином, він просто сидить там, але перший раз, коли інший модуль намагається викликати цю властивість, він перевіряє, чи є базове поле нульовим - якщо воно є, воно продовжує і завантажує його, невідомо модулю, що викликає. Це може значно пришвидшити ініціалізацію об'єкта.
  • Брудне відстеження: Про що я насправді дізнався з власного запитання тут, на StackOverflow. Коли у мене дуже багато об'єктів, значення яких могли змінитися під час виконання, я можу використовувати властивість для відстеження, чи потрібно їх зберігати в базі даних чи ні. Якщо жодне властивість об'єкта не змінилося, прапор IsDirty не буде відключений, а тому функція збереження буде пропускати його, вирішуючи, що потрібно повернути до бази даних.

1
Питання про брудне відстеження: що робити, якщо я можу змінити поле безпосередньо - не знаю, чи це можна зробити, я можу сказати: "об'єкт не потрібно зберігати, якщо не змінилося жодне ПОЛЕ об'єкта" таким чином брудне відстеження не буде різницею, я щось пропускаю?
сайти

2
@juanpastas: Перевага властивостей щодо брудного відстеження полягає в тому, що якщо налаштування властивостей встановить "брудний" прапор, то в сценарії, коли прапор не встановлений, код не повинен буде перевіряти значення будь-яких властивостей, щоб побачити якби вони могли змінитися. На противагу цьому, якщо об’єкт виставляє свої атрибути як поля, то вміст усіх полів повинен порівнюватися з попереднім значенням (що не тільки додає часу на порівняння, але також означає, що код повинен мати попереднє значення).
supercat

Це хороші. Це також дозволяє запускати методи (як події) або вести журнал, коли значення встановлюється чи читається.
coloboxp

54

Використовуючи Властивості, ви можете викликати подію, коли змінюється значення властивості (ака. PropertyChangedEvent) або перед зміною значення для підтримки скасування.

Це неможливо за допомогою (прямого доступу до) полів.

public class Person {
 private string _name;

 public event EventHandler NameChanging;     
 public event EventHandler NameChanged;

 public string Name{
  get
  {
     return _name;
  }
  set
  {
     OnNameChanging();
     _name = value;
     OnNameChanged();
  }
 }

 private void OnNameChanging(){       
     NameChanging?.Invoke(this,EventArgs.Empty);       
 }

 private void OnNameChanged(){
     NameChanged?.Invoke(this,EventArgs.Empty);
 }
}

3
Мені знадобилося багато часу, щоб знайти це. Це MVVM . Дякую ! :)

46

Оскільки багато хто з них пояснили технічні плюси і мінуси, Propertiesі Fieldнастав час перейти до прикладів реального часу.

1. Властивості дозволяють встановити рівень доступу лише для читання

Розглянемо випадок dataTable.Rows.Countі dataTable.Columns[i].Caption. Вони походять з класу, DataTableі обидва є для нас публічними. Різниця рівня доступу до них полягає в тому, що ми не можемо встановлювати значення, dataTable.Rows.Countале ми можемо читати і писати dataTable.Columns[i].Caption. Це можливо через Field? Ні!!! Це можна зробити Propertiesтільки за допомогою.

public class DataTable
{
    public class Rows
    {       
       private string _count;        

       // This Count will be accessable to us but have used only "get" ie, readonly
       public int Count
       {
           get
           {
              return _count;
           }       
       }
    } 

    public class Columns
    {
        private string _caption;        

        // Used both "get" and "set" ie, readable and writable
        public string Caption
        {
           get
           {
              return _caption;
           }
           set
           {
              _caption = value;
           }
       }       
    } 
}

2. Властивості в PropertyGrid

Можливо, ви працювали Buttonв Visual Studio. Його властивості відображаються PropertyGridподібним чином Textі Nameт. Д. Коли ми перетягуємо кнопку і коли ми натискаємо на властивості, вона автоматично знайде клас Buttonі фільтри Propertiesта покаже, що в PropertyGrid(де PropertyGridвони не відображатимуться, Fieldхоча вони є загальнодоступними).

public class Button
{
    private string _text;        
    private string _name;
    private string _someProperty;

    public string Text
    {
        get
        {
           return _text;
        }
        set
        {
           _text = value;
        }
   } 

   public string Name
   {
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   } 

   [Browsable(false)]
   public string SomeProperty
   {
        get
        {
           return _someProperty;
        }
        set
        {
           _someProperty= value;
        }
   } 

В PropertyGrid, властивості Nameі Textбудуть показані, але ні SomeProperty. Чому ??? Оскільки властивості можуть приймати атрибути . Він не відображається у випадку, коли [Browsable(false)]помилковий.

3. Може виконувати оператори всередині Властивості

public class Rows
{       
    private string _count;        


    public int Count
    {
        get
        {
           return CalculateNoOfRows();
        }  
    } 

    public int CalculateNoOfRows()
    {
         // Calculation here and finally set the value to _count
         return _count;
    }
}

4. У джерелі прив'язки можна використовувати лише властивості

Джерело прив'язки допомагає нам зменшити кількість рядків коду. Fieldsне приймаються BindingSource. Ми повинні використовувати Propertiesдля цього.

5. Режим налагодження

Подумайте, ми використовуємо, Fieldщоб утримати значення. У якийсь момент нам потрібно налагодити і перевірити, де значення стає нульовим для цього поля. Це буде важко зробити там, де кількість рядків коду перевищує 1000. У таких ситуаціях ми можемо використовувати Propertyі встановлювати режим налагодження всередині Property.

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }

Це цікаві факти, але ви пропускаєте точку філософії полів та властивостей.
Девід Ференчі Рогожан

Що ти означає ФІЛІЗОФІЯ ? @Dawid Ferenczy
Сарат Аванаву

Дивіться, наприклад, марковану відповідь. Але ви помітили, що ви просто надаєте приклади використання, оскільки різниця між полями та властивостями вже була описана, тому забув мій коментар, будь ласка :)
David Ferenczy Rogožan

2
Прочитайте моє перше речення у моїй відповіді. Я спеціально сказав, що не збираюсь тут все повторювати знову. Це безглуздя!!! Люди спочатку подивляться на опис, потім на приклади. Позначена відповідь добре описує, але я додав кілька сценаріїв та прикладів у реальному часі, що має сенс. Будь ласка, переконайтесь, що ви думаєте з точки зору читача, перш ніж коментувати @Dawid Ferenczy
Сарат Аванаву

1
Я прочитав це, але ви не прочитали попереднього коментаря, очевидно: " Але ви помітили, що ви просто надаєте приклади використання, оскільки різниця між полями та властивостями вже була описана, тому забув мій коментар, будь ласка :) " .
David Ferenczy Rogožan

32

РІЗНИКИ - ВИКОРИСТАННЯ (коли і чому)

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

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


Це приголомшлива відповідь, дійсно допомогла мені зрозуміти це.
Стів Бауман

14

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

Якщо ви пишете бібліотеку класів, розроблену для широкого споживання (наприклад, .NET Framework, якою користуються мільйони людей), це може бути проблемою. Однак якщо ви пишете клас, який використовується внутрішньо всередині невеликої бази коду (скажімо, <= 50 K рядків), це насправді не велика справа, тому що ніхто не буде негативно впливати на ваші зміни. У цьому випадку це дійсно просто зводиться до особистих переваг.


11

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

Властивості можуть працювати дуже довго, матимуть побічні ефекти та навіть можуть спричинити винятки. Поля швидкі, без побічних ефектів, і ніколи не кидають винятків. Через побічні ефекти властивість може повертати інше значення для кожного дзвінка (як це може бути у випадку DateTime.Now, тобто DateTime.Now не завжди дорівнює DateTime.Now). Поля завжди повертають однакове значення.

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

Властивості підтримують рівень абстракції, інкапсулюючи все, що означає отримати / встановити значення.

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


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

1
Властивості ніколи не повинні мати побічних ефектів. Навіть налагоджувач припускає, що може оцінити їх безпечно.
Крейг Гідні

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

11

На задньому плані властивість компілюється у методи. Отже, Nameвластивість компілюється у get_Name()та set_Name(string value). Це можна побачити, якщо вивчити складений код. Таким чином, є (дуже) невеликі накладні витрати при їх використанні. Зазвичай ви завжди будете використовувати властивість, якщо виставляєте поле зовні, і ви часто будете використовувати його всередині, якщо вам потрібно зробити перевірку значення.


7

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

Наприклад, якщо у мене є змінні, названі як "id" та "name", які є приватними, але може виникнути ситуація, коли ця змінна потрібна для операції читання / запису поза класом. У цій ситуації властивість може допомогти мені отримати цю змінну для читання / запису залежно від параметра get / set, визначеного для властивості. Властивість може бути лише читання / запис лише / readwrite.

ось демонстрація

class Employee
{
    // Private Fields for Employee
    private int id;
    private string name;

    //Property for id variable/field
    public int EmployeeId
    {
       get
       {
          return id;
       }
       set
       {
          id = value;
       }
    }

    //Property for name variable/field
    public string EmployeeName
    {
       get
       {
          return name;
       }
       set
       {
          name = value;
       }
   }
}

class MyMain
{
    public static void Main(string [] args)
    {
       Employee aEmployee = new Employee();
       aEmployee.EmployeeId = 101;
       aEmployee.EmployeeName = "Sundaran S";
    }
}

6

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

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

Але є одна перевага, що поля мають над властивостями, і це їх здатність використовувати як параметри "ref" / "out". Припустимо, у вас є метод із такою підписом:

public void TransformPoint(ref double x, ref double y);

і припустимо, що ви хочете використовувати цей метод для перетворення масиву, створеного так:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

Ось я думаю, що це найшвидший спосіб зробити це, оскільки X і Y - це властивості:

for (int i = 0; i < points.Length; i++)
{
    double x = points[i].X;
    double y = points[i].Y;
    TransformPoint(ref x, ref y);
    points[i].X = x;
    points[i].Y = y;
}

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

internal struct MyPoint
{
    internal double X;
    internal double Y;
}

// ...

MyPoint[] points = new MyPoint[1000000];
Initialize(points);

// ...

for (int i = 0; i < points.Length; i++)
{
    TransformPoint(ref points[i].X, ref points[i].Y);
}

Здійснюючи деякі вимірювання самостійно, версія з полями займає приблизно 61% часу як версія з властивостями (.NET 4.6, Windows 7, x64, режим випуску, не додається відладчик). Чим дорожчий TransformPointметод стає, тим менш вираженою стає різниця. Щоб повторити це самостійно, запустіть перший коментар із рядка, коментуючи його, і не коментуйте його.

Навіть якби не було переваг для продуктивності для вищезазначених, є й інші місця, де можливість використання параметрів ref та out може бути корисною, наприклад, при виклику методу сімейства Interlocked або Volatile . Примітка. Якщо це нове для вас, Volatile - це в основному спосіб отримати таку саму поведінку, яку надає volatileключове слово. Таким чином, volatileвін , як магічно, не вирішує всі проблеми, пов’язані з безпекою потоків, як наголошує його назва.

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


6

Хоча поля та властивості схожі між собою, вони є 2 абсолютно різними мовними елементами.

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

  2. Властивості, з іншого боку, ніколи не зберігають дані. Вони є лише парами методів (get and set), які можна синтаксично викликати аналогічно як поля, і в більшості випадків вони отримують доступ (для читання чи запису) поля, що є джерелом певної плутанини. Але оскільки властивості методів є (з деякими обмеженнями на зразок фіксованого прототипу) звичайними методами C #, вони можуть робити все, що може робити звичайний метод. Це означає, що вони можуть мати 1000 рядків коду, вони можуть кидати винятки, викликати інші методи, можуть бути навіть віртуальними, абстрактними або переопределеними. Що робить властивості особливими, це той факт, що компілятор C # зберігає додаткові метадані в збори, які можна використовувати для пошуку конкретних властивостей - широко використовуваної функції.

Методи отримання та встановлення властивостей мають такі прототипи.

PROPERTY_TYPE get();

void set(PROPERTY_TYPE value);

Таким чином, це означає, що властивості можна "емулювати" шляхом визначення поля та 2 відповідних методів.

class PropertyEmulation
{
    private string MSomeValue;

    public string GetSomeValue()
    {
        return(MSomeValue);
    }

    public void SetSomeValue(string value)
    {
        MSomeValue=value;
    }
}

Така емуляція властивостей типова для мов програмування, які не підтримують властивості - як стандартний C ++. У C # там завжди слід віддавати перевагу властивостям як способу доступу до ваших полів.

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

class OneHundredFields
{
        public int Field1;
        public int Field2;
        ...
        public int Field100;
}

OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.

class OneHundredProperties
{
    public int Property1
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    public int Property2
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }

    ...

    public int Property100
    {
        get
        {
            return(1000);
        }
        set
        {
            // Empty.
        }
    }
}

OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).

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

  1. Робити поля загальнодоступними - недоцільно.
  2. Використання властивостей.

Ось клас із використанням публічних полів.

class Name
{
    public string FullName;
    public int YearOfBirth;
    public int Age;
}

Name name=new Name();

name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;

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

name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;

Код дійсний, всі завдання виконуватимуться, хоча вони нелогічні. Ageмає негативне значення, YearOfBirthзнаходиться далеко в майбутньому і не відповідає віку та FullNameє нульовим. За допомогою полів ви не можете перешкодити користувачам class Nameробити такі помилки.

Ось код із властивостями, який вирішує ці проблеми.

class Name
{
    private string MFullName="";
    private int MYearOfBirth;

    public string FullName
    {
        get
        {
            return(MFullName);
        }
        set
        {
            if (value==null)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MFullName=value;
        }
    }

    public int YearOfBirth
    {
        get
        {
            return(MYearOfBirth);
        }
        set
        {
            if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
            {
                throw(new InvalidOperationException("Error !"));
            }

            MYearOfBirth=value;
        }
    }

    public int Age
    {
        get
        {
            return(DateTime.Now.Year-MYearOfBirth);
        }
    }

    public string FullNameInUppercase
    {
        get
        {
            return(MFullName.ToUpper());
        }
    }
}

Оновлена ​​версія класу має такі переваги.

  1. FullNameі YearOfBirthперевіряються на недійсні значення.
  2. Ageне підлягає написанню. Це обчислюється з YearOfBirthпоточного року.
  3. Нова властивість FullNameInUppercaseперетворюється FullNameна ГОЛОВНУ СЛУЧАЮ. Це трохи надуманий приклад використання властивостей, коли властивості зазвичай використовуються для подання значень поля у форматі, який є більш підходящим для користувача - наприклад, використовуючи поточну локаль у конкретному числовому DateTimeформаті.

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

C # також підтримує індексатори, які є властивостями, які мають параметр індексу в методах властивостей. Ось приклад.

class MyList
{
    private string[]                 MBuffer;

    public MyList()
    {
        MBuffer=new string[100];
    }

    public string this[int Index]
    {
        get
        {
            return(MBuffer[Index]);
        }
        set
        {
            MBuffer[Index]=value;
        }
    }
}

MyList   List=new MyList();

List[10]="ABC";
Console.WriteLine(List[10]);

Оскільки C # 3.0 дозволяє визначати автоматичні властивості. Ось приклад.

class AutoProps
{
    public int Value1
    {
        get;
        set;
    }

    public int Value2
    {
        get;
        set;
    }
}

Хоча він class AutoPropsмістить лише властивості (або це схоже), він може зберігати 2 значення, а розмір об'єктів цього класу дорівнює sizeof(Value1)+sizeof(Value2)= 4 + 4 = 8 байт.

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

Ось код, сформований ILSpy від складеної збірки. Клас містить генеровані приховані поля та властивості.

internal class AutoProps
{
    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value1>k__BackingField;

    [CompilerGenerated]
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private int <Value2>k__BackingField;

    public int Value1
    {
        [CompilerGenerated]
        get
        {
            return <Value1>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value1>k__BackingField = value;
        }
    }

    public int Value2
    {
        [CompilerGenerated]
        get
        {
            return <Value2>k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            <Value2>k__BackingField = value;
        }
    }
}

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

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

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


4

Також властивості дозволяють використовувати логіку при встановленні значень.

Таким чином, ви можете сказати, що ви хочете встановити значення лише на ціле поле, якщо значення більше x, інакше киньте виняток.

Дійсно корисна функція.


4

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


1
відколи? заблокуйте поле резервного
зберігання

1
Властивості - це методи, які сьогодні не накреслюються жодним CIL JIT. Якщо ви збираєтесь використовувати примітивні нитки, такі як Interlocked, вам потрібно мати поля. Перевірте свої джерела. Справді, "блокування" було неправильним словом.
Джонатан C Дікінсон,

4

(Це дійсно має бути коментар, але я не можу публікувати коментар, тому, будь ласка, вибачте, якщо це не підходить як повідомлення).

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

get { return _afield; }
set { _afield = value; }

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

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


Оскільки C # 3.0 , описаний тут візерунок зручно підтримувати функцією під назвою " Авто-реалізовані властивості" .
DavidRR

Я думаю, що одна із переваг у C # із властивостями, оскільки вони мають той самий API, що й поля, тому клієнти класу насправді не хвилюються, чи отримують вони доступ до властивості чи поля. (Це, наприклад, НЕ вірно в C ++). При прототипуванні я вважаю, що розумно почати з публічних полів, а потім перейти до властивостей за потребою. Існує враження про продуктивність та пам'ять із властивостями, а також є додаткове введення тексту. Вони не безкоштовні. Але якщо ви передумаєте, вам не потрібно буде переробляти будь-який залежний код.
Марк Лаката

Властивості не можна використовувати як параметри OUT або REF, тому зміна поля у властивість може призвести до компіляції помилок у рядку. Якби значення було реалізовано як властивість з самого початку, воно ніколи не використовувалося б як параметри OUT або REF (VAR в Pascal / Delphi), і будь-які зміни, внесені в getter / setter, були б прозорими для використання.
HeartWare

4

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


4

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

  class SomeClass
  {
     int numbera; //Field

     //Property 
    public static int numbera { get; set;}

  }

3

Властивості інкапсулюють поля, тим самим дозволяючи виконувати додаткову обробку значення, яке потрібно встановити чи отримати. Зазвичай, надмірне використання властивостей, якщо ви не робите жодної перед- або післяобробної обробки значення поля.


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

Щодо еволюції API, ви можете без проблем використовувати поля для приватних даних. Також у непарних випадках, коли потрібно обмінюватися даними в межах збірки, ви можете надати "внутрішній" доступ до полів.
Даніель Ервікер

3

IMO, Властивості - це лише функції функцій / методів / інтерфейсів / SetXXX () "" GetXXX () ", які ми використовували раніше, але вони більш стислі та елегантні.


3

Традиційно приватні поля задаються методами getter та setter. Для меншого коду ви можете використовувати властивості для встановлення полів.


3

коли у вас є клас "Автомобіль". Властивості - колір, форма ..

Де як поля є змінними, визначеними в межах класу.


3

З Вікіпедії - Об'єктно-орієнтоване програмування :

Об'єктно-орієнтоване програмування (OOP) - парадигма програмування, заснована на понятті "об'єкти", це структури даних, що містять дані у вигляді полів , часто відомих як атрибути; і код у вигляді процедур, часто відомих як методи . (наголос додано)

Властивості насправді є частиною поведінки об'єкта, але розроблені для того, щоб надати споживачам об'єкта ілюзію / абстракцію роботи з даними об’єкта.


3

Моя конструкція поля полягає в тому, що поле потрібно змінювати тільки його батьківським, звідси і класом. У результаті змінна стає приватною, тож, щоб мати право читати класи / методи за межами, я проходжу систему властивостей лише з Get. Потім це поле витягується властивістю та лише для читання! Якщо ви хочете змінити його, вам доведеться пройти методи (наприклад, конструктор), і я вважаю, що завдяки такому способу зробити вас захищеними, ми маємо кращий контроль над нашим кодом, тому що ми "фланець". Можливо, завжди можна все оприлюднити, тому кожен можливий випадок, поняття змінних / методів / класів тощо ... на мою думку, це лише допомога в розробці, підтримці коду. Наприклад, якщо людина поновлює код із загальнодоступними полями, він може робити все, що завгодно, і тому речі "нелогічні" по відношенню до об'єктивної, логіки того, чому був написаний код. Це моя точка зору.

Коли я використовую класичну модель приватних полів / публічних властивостей для читання лише для 10 полів приватних осіб, я повинен написати 10 публічних властивостей! Код може бути дійсно більшим швидше. Я відкриваю приватний сетер, і тепер я використовую лише загальнодоступні ресурси з приватним сеттером. Сетер створює у фоновому режимі приватне поле.

Тому мій старий класичний стиль програмування:

public class MyClass
{
 private int _id;
 public int ID { get { return _id; } }
 public MyClass(int id)
 {
  _id = id;
 }
}

Мій новий стиль програмування:

public class MyClass
{
 public int ID { get; private set; }
 public MyClass(int id)
 {
  ID = id;
 }
}

Ага моє погано, вибачте!
Тоні Піно

3

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

class Room {
   public string sectionOne;
   public string sectionTwo;
}

Room r = new Room();
r.sectionOne = "enter";

Люди потрапляють до розділуОдин досить легко, перевірки не було

class Room 
{
   private string sectionOne;
   private string sectionTwo;

   public string SectionOne 
   {
      get 
      {
        return sectionOne; 
      }
      set 
      { 
        sectionOne = Check(value); 
      }
   }
}

Room r = new Room();
r.SectionOne = "enter";

Тепер ви перевірили людину і знаєте, чи є в нього щось зло


3

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

Властивості схожі на поля, оскільки вони визначають стани та дані, пов'язані з об'єктом.

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


2

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

Наприклад, візьмемо клас з іменем Employee, з приватними полями для імені, віку та Employee_Id. Ми не можемо отримати доступ до цих полів поза класом, але ми можемо отримати доступ до цих приватних полів через властивості.

Чому ми використовуємо властивості?

Робити поле публічним та відкривати поле класу ризиковано, оскільки ви не будете контролювати те, що отримується та повертається.

Щоб зрозуміти це чітко на прикладі, давайте взяти клас учня, який має посвідчення особи, паспорт, ім'я. Зараз у цьому прикладі певна проблема з публічним полем

  • Ідентифікатор не повинен бути -ve.
  • Ім'я не можна встановити на нуль
  • Мітка пропуску повинна бути лише для читання.
  • Якщо відсутнє ім'я студента, No Name не повертається.

Для усунення цієї проблеми ми використовуємо метод Get and set.

// A simple example
public class student
{
    public int ID;
    public int passmark;
    public string name;
}

public class Program
{
    public static void Main(string[] args)
    {
       student s1 = new student();
       s1.ID = -101; // here ID can't be -ve
       s1.Name = null ; // here Name can't be null
    }
}

Тепер ми беремо приклад методу get and set

public class student
{
    private int _ID;
    private int _passmark;
    private string_name ;
    // for id property
    public void SetID(int ID)
    {
        if(ID<=0)
        {
            throw new exception("student ID should be greater then 0");
        }
        this._ID = ID;
    }
    public int getID()
    {
        return_ID;
    }
}
public class programme
{
    public static void main()
    {
        student s1 = new student ();
        s1.SetID(101);
    }
    // Like this we also can use for Name property
    public void SetName(string Name)
    {
        if(string.IsNullOrEmpty(Name))
        {
            throw new exeception("name can not be null");
        }
        this._Name = Name;
    }
    public string GetName()
    {
        if( string.IsNullOrEmpty(This.Name))
        {
            return "No Name";
        }
        else
        {
            return this._name;
        }
    }
        // Like this we also can use for Passmark property
    public int Getpassmark()
    {
        return this._passmark;
    }
}

2

Додаткова інформація: За замовчуванням отримати та встановити аксесуари настільки ж доступні, як і сама власність. Ви можете керувати / обмежувати доступність доступу до користувачів окремо (для отримання та встановлення), застосовуючи на них більш обмежувальні модифікатори доступу.

Приклад:

public string Name
{
    get
    {
        return name;
    }
    protected set
    {
        name = value;
    }
}

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


2

Властивості використовуються для викриття поля. Вони використовують аксесуари (встановити, отримати), за допомогою яких значення приватних полів можна читати, записувати чи маніпулювати.

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

Використовуючи властивості, ми можемо встановити перевірку типу даних, які встановлюються в полі.

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

Ми можемо зробити це двома способами, використовуючи getter та setters та використовуючи властивість.

 Using Getter and Setter

    // field
    private int _age;

    // setter
    public void set(int age){
      if (age <=0)
       throw new Exception();

      this._age = age;
    }

    // getter
    public int get (){
      return this._age;
    }

 Now using property we can do the same thing. In the value is a key word

    private int _age;

    public int Age{
    get{
        return this._age;
    }

    set{
       if (value <= 0)
         throw new Exception()
       }
    }

Властивість, реалізована автоматично, якщо ми не дотримуємося логіки в отриманні та встановленні аксесуарів, ми можемо використовувати властивість, реалізовану автоматично.

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

public int Age{get;set;}

Властивості абстрактних Абстрактний клас може мати абстрактне властивість, яке слід реалізувати у похідному класі

public abstract class Person
   {
      public abstract string Name
      {
         get;
         set;
      }
      public abstract int Age
      {
         get;
         set;
      }
   }

// overriden something like this
// Declare a Name property of type string:
  public override string Name
  {
     get
     {
        return name;
     }
     set
     {
        name = value;
     }
  }

Ми можемо приватно встановити властивість. У цьому ми можемо приватно встановити властивість авто (встановлено у класі)

public int MyProperty
{
    get; private set;
}

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

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}

2

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

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

Але в інших випадках, як клас Math (Система імен систем), є кілька статичних властивостей, які вбудовані в клас. одна з яких - математична константа PI

напр. Math.PI

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

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