В чем разница между полем и свойством?


1131

Что в C # отличает поле от свойства и когда следует использовать поле вместо свойства?


32
Microsoft напрямую отвечает на этот вопрос (для всех языков .NET) в рамках своих рекомендаций для участников . Подробности смотрите в статьях « Дизайн недвижимости» и « Дизайн поля» . Обратите внимание, что существует различие между членами экземпляра и статическими членами.
DavidRR

Ответы:


979

Свойства выставляют поля. Поля должны (почти всегда) быть приватными для класса и доступны через свойства get и 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
Стоит отметить, что свойства не обязательны для инкапсуляции полей. Там не может быть никакого поля за собственностью. Это может быть вычисление или возврат константы или что-то еще.
Кент Boogaart

9
«не влияя на внешний вид, к которому обращаются вещи, которые используют ваш класс». простите, если я неправильно понимаю, тогда, но зачем вообще нужны модификаторы доступа перед свойствами, если поле позади этого, кажется, справляется с этим? то есть зачем делать что-либо, кроме публичного?
Чаки

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

6
@jpaugh Если я являюсь потребителем класса, я выполняю контракты, установленные создателем класса. Если свойство есть string, мой контракт: назначить любые символы до ~ 2bil длины. Если свойство есть DateTime, мой контракт: назначить любые числа в пределах DateTime, которые я могу посмотреть. Если создатель добавляет ограничения в установщики, эти ограничения не передаются. Но если вместо этого создатель изменяет тип с stringна Surname, то его новый класс Фамилия сообщает об ограничениях, и свойство public Surname LastNameне имеет проверки установщика. Кроме того, Surnameявляется многоразовым.
Суамер

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 за упоминание autoperperties - я думаю, что это то, что многие ответы здесь (и в других местах) забыли ввести. Без этого объяснения все еще может быть довольно трудно понять, что на public int myVar { get; set; }самом деле означает (и я предполагаю, что это причина как минимум 50% показов получает этот вопрос).
Прииду Нимре 24

7
+1 также за упоминание auto и упоминание того, как оно работает («AutoProperty создает для нас личное поле»). Это был ответ, который я искал на мой вопрос. Во время исследования я не видел на странице MSDN о них никаких признаков того, что частное поле было создано и вызывает путаницу. Я думаю, что это значит? «Атрибуты разрешены для автоматически внедряемых свойств, но, очевидно, не для вспомогательных полей, поскольку они недоступны из вашего исходного кода. Если вы должны использовать атрибут в вспомогательном поле свойства, просто создайте обычное свойство». но не был уверен.
Ныра

3
Обратите внимание, что данный пример не содержит приседания. Это свойство дает 100% полный доступ к приватному полю, поэтому оно не является объектно-ориентированным. В этом случае у вас также может быть открытое поле. Конечно, это помогает (незначительно) реорганизовать код в будущем, но любая интегрированная среда разработки может трансформировать поле в свойство с помощью нескольких нажатий клавиш. Ответ может быть технически правильным о том, как работают свойства, но он не дает хорошего «объяснения ООП» их использованию.
Сара

2
@kai Я согласен, что ответ слишком упрощен и не показывает всю мощь авто-свойства, однако я не согласен, что это не объектно-ориентированный. Вы можете проверить разницу между полями и свойствами . Поля не могут быть виртуальными, а virtualсами являются частью объектно-ориентированного программирования.
Гоб

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

164

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


98

Я дам вам несколько примеров использования свойств, которые могут привести к вращению шестерен:

  • Ленивая инициализация : если у вас есть свойство объекта, которое дорого загружать, но к которому обычно не обращаются при обычных запусках кода, вы можете отложить его загрузку через свойство. Таким образом, он просто сидит там, но в первый раз, когда другой модуль пытается вызвать это свойство, он проверяет, является ли нижележащее поле пустым - если это так, он идет вперед и загружает его, неизвестно вызывающему модулю. Это может значительно ускорить инициализацию объекта.
  • Грязное отслеживание: о чем я действительно узнал из своего собственного вопроса здесь, на StackOverflow. Когда у меня много объектов, значения которых могли измениться во время выполнения, я могу использовать это свойство, чтобы отслеживать, нужно ли их сохранять обратно в базу данных или нет. Если ни одно свойство объекта не изменилось, флаг IsDirty не сработает, и, следовательно, функция сохранения пропустит его при принятии решения о том, что необходимо вернуть в базу данных.

1
Вопрос о грязном отслеживании: что, если бы я мог изменить поле напрямую - я не знаю, можно ли это сделать, я мог бы сказать: «объект не нужно сохранять, если не было изменено ни одно ПОЛЕ объекта». таким образом, грязное отслеживание не будет иметь значения, я что-то упустил?
сайты

2
@juanpastas: Преимущество свойств в отношении «грязного» отслеживания состоит в том, что если установщики свойств установят «грязный» флаг, то в сценарии, где этот флаг не установлен, код не должен будет проверять значения каких-либо свойств, чтобы увидеть если бы они могли измениться. Напротив, если объект предоставляет свои атрибуты как поля, то содержимое всех полей должно сравниваться с предыдущим значением (что не только добавляет время для сравнения, но также означает, что код должен иметь предыдущее значение).
суперкат

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

54

Используя Свойства, вы можете вызвать событие, когда значение свойства изменяется (aka. 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. В Binding Source можно использовать только свойства

Binding Source помогает нам уменьшить количество строк кода. 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;
        }
   }

Это интересные факты, но вам не хватает философии полей и свойств.
Дэвид Ференци Рогожан

Что ты подразумеваешь под ФИЛИСОФИЕЙ ? @ Давид Ференчи
Сарат Аванаву

Смотрите, например, помеченный ответ. Но вы заметили, что вы просто предоставляете примеры использования, так как разница между полями и свойствами уже была описана, поэтому забыл мой комментарий, пожалуйста :)
David Ferenczy Rogožan

2
Прочитайте мое первое предложение в моем ответе. Я специально сказал, что я не собираюсь повторять здесь все снова. Это бессмысленно!!! Сначала люди посмотрят описание, затем примеры. Отмеченный ответ дает хорошее описание, но я добавил несколько сценариев и примеров в реальном времени, что имеет смысл. Пожалуйста, убедитесь, что вы думаете с точки зрения читателя, прежде чем комментировать @Dawid Ferenczy
Sarath Avanavu

1
Я читал его, но вы не читали мой предыдущий комментарий, очевидно: « Но вы заметили, что вы просто предоставляете примеры использования, поскольку различие между полями и свойствами уже было описано, поэтому забыл мой комментарий, пожалуйста :) » ,
Давид Ференци Рогожан

32

ОТЛИЧИЯ - ИСПОЛЬЗОВАНИЕ (когда и почему)

Поле является переменной , которая объявляется непосредственно в классе или структуры. Класс или структура могут иметь поля экземпляра или статические поля или оба. Как правило, вы должны использовать поля только для переменных, которые имеют частную или защищенную доступность . Данные, которые ваш класс предоставляет клиентскому коду, должны предоставляться через методы, свойства и индексаторы. Используя эти конструкции для косвенного доступа к внутренним полям, вы можете защититься от недопустимых входных значений.

Свойство является элементом , который обеспечивает гибкий механизм для чтения, записи или вычислений значения частной области. Свойства можно использовать так, как будто они являются открытыми членами данных, но на самом деле это специальные методы, называемые методами доступа . Это позволяет легко получать доступ к данным, а также способствует безопасности и гибкости методов . Свойства позволяют классу предоставлять открытый способ получения и установки значений, скрывая при этом код реализации или проверки. Метод доступа к свойству get используется для возврата значения свойства, а метод доступа к set используется для назначения нового значения.


Это потрясающий ответ, действительно помог мне понять это.
Стив Бауман

14

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

Если вы пишете библиотеку классов, предназначенную для широкого потребления (например, .NET Framework, которой пользуются миллионы людей), это может стать проблемой. Однако, если вы пишете класс, используемый внутри небольшой базы кода (скажем, <= 50 тыс. Строк), это на самом деле не имеет большого значения, потому что ваши изменения ни на кого не повлияют. В этом случае все сводится к личным предпочтениям.


11

Свойства поддерживают асимметричный доступ, т. Е. Вы можете иметь либо геттер и сеттер, либо только один из двух. Точно так же свойства поддерживают индивидуальную доступность для getter / setter. Поля всегда симметричны, то есть вы всегда можете получить и установить значение. Исключением являются поля только для чтения, которые, очевидно, не могут быть установлены после инициализации.

Свойства могут работать очень долго, иметь побочные эффекты и даже создавать исключения. Поля быстрые, без побочных эффектов и никогда не будут генерировать исключения. Из-за побочных эффектов свойство может возвращать различное значение для каждого вызова (как может иметь место в случае DateTime.Now, то есть DateTime.Now не всегда равен DateTime.Now). Поля всегда возвращают одно и то же значение.

Поля могут использоваться для параметров out / ref, свойства - нет. Свойства поддерживают дополнительную логику - это может быть использовано для реализации отложенной загрузки среди прочего.

Свойства поддерживают уровень абстракции, инкапсулируя все, что это означает, чтобы получить / установить значение.

Используйте свойства в большинстве случаев, но старайтесь избегать побочных эффектов.


У полей могут быть все проблемы стоимости свойств, когда тип данных поля - это объект с перегрузкой оператора преобразования - это тонкая ошибка.
Энди Дент

1
Свойства никогда не должны иметь побочных эффектов. Даже отладчик предполагает, что он может оценить их безопасно.
Крейг Гидни

@Strilanc: Я полностью согласен, однако, это не всегда так. Что касается отладчика, есть много проблем с FuncEval, если это то, о чем вы говорите.
Брайан Расмуссен

11

В фоновом режиме свойство компилируется в методы. Таким образом, Nameсвойство компилируется в get_Name()и set_Name(string value). Вы можете увидеть это, если изучите скомпилированный код. Таким образом, при их использовании возникают (очень) небольшие потери производительности. Обычно вы всегда будете использовать свойство, если вы выставляете поле снаружи, и вы часто будете использовать его внутри, если вам нужно проверить значение.


7

Если вы хотите, чтобы ваша личная переменная (поле) была доступна для объекта вашего класса из других классов, вам нужно создать свойства для этих переменных.

например, если у меня есть переменные с именами «id» и «name», которые являются частными, но может быть ситуация, когда эта переменная необходима для операции чтения / записи вне класса. В этой ситуации свойство может помочь мне получить эту переменную для чтения / записи в зависимости от получения / набора, определенного для свойства. Свойство может быть доступно только для чтения / записи только / чтения.

вот демо

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 и 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, вам нужно иметь поля. Проверьте свои источники. По общему признанию, «блокировка» была неправильным словом для использования.
Джонатан С Дикинсон

4

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

Однажды я работал в месте, где рекомендуемой практикой было использование открытых полей вместо свойств, когда эквивалентное свойство def просто обращалось к полю, как в:

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

Их аргументация заключалась в том, что публичное поле может быть преобразовано в собственность позже в будущем, если потребуется. В то время это казалось мне немного странным. Судя по этим постам, похоже, что не многие здесь согласятся. Что вы могли бы сказать, чтобы попытаться что-то изменить?

Редактировать: я должен добавить, что вся база кода в этом месте была скомпилирована одновременно, поэтому они могли подумать, что изменение открытого интерфейса классов (путем изменения открытого поля для свойства) не было проблемой.


Начиная с C # 3.0 , описанный здесь шаблон удобно поддерживается функцией, называемой автоматически реализованными свойствами .
DavidRR

Я думаю, что одно из преимуществ в C # со свойствами - они имеют тот же API, что и поля, поэтому клиентам этого класса все равно, обращаются ли они к свойству или полю. (Это НЕ верно для C ++, например). В прототипировании, я думаю, разумно начать с открытых полей, а затем перейти к свойствам по мере необходимости. Это приводит к снижению производительности и памяти со свойствами, а также к дополнительному типированию. Они не бесплатны. Но, если вы передумаете, вам не потребуется рефакторинг любого зависимого кода.
Марк Лаката

Свойства нельзя использовать в качестве параметров OUT или REF, поэтому изменение поля в свойстве может привести к ошибкам компиляции в конце строки. Если бы значение было реализовано как свойство с самого начала, то оно никогда не использовалось бы как параметры OUT или REF (VAR в Pascal / Delphi), и любое изменение, которое вы вносите в метод получения / установки, будет прозрачным для использования.
HeartWare

4

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


4

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

  class SomeClass
  {
     int numbera; //Field

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

  }

3

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


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

Что касается развития API, вы можете без проблем использовать поля для личных данных. Также в нечетных случаях, когда вы хотите обмениваться данными в сборке, вы можете предоставить полям «внутренний» доступ.
Дэниел Эрвикер

3

IMO, свойства - это просто пары функций / методов / интерфейсов "SetXXX ()" "GetXXX ()", которые мы использовали ранее, но они более лаконичны и элегантны.


3

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


3

когда у вас есть класс, который "Автомобиль". Свойства цвета, формы ..

Где поля - это переменные, определенные в области видимости класса.


3

Из Википедии - Объектно-ориентированное программирование :

Объектно-ориентированное программирование (ООП) - это парадигма программирования, основанная на концепции «объектов», которые представляют собой структуры данных, которые содержат данные в форме полей , часто называемых атрибутами; и код в форме процедур, часто называемых методами . (выделение добавлено)

Свойства на самом деле являются частью поведения объекта, но предназначены для того, чтобы предоставить потребителям объекта иллюзию / абстракцию работы с данными объекта.


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. Мы не можем получить доступ к этим полям извне класса, но мы можем получить доступ к этим частным полям через свойства.

Почему мы используем свойства?

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

Чтобы понять это на примере, давайте возьмем класс ученика, у которого есть ID, пароль, имя. Теперь в этом примере некоторые проблемы с открытым полем

  • Идентификатор не должен быть -ве.
  • Имя не может быть установлено на ноль
  • Проходной балл должен быть только для чтения.
  • Если имя ученика отсутствует, имя не должно быть возвращено.

Чтобы устранить эту проблему, мы используем метод Get и 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 и 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

Дополнительная информация: По умолчанию методы доступа get и set доступны так же, как и само свойство. Вы можете контролировать / ограничивать доступ к средствам доступа индивидуально (для получения и установки), применяя к ним более ограничивающие модификаторы доступа.

Пример:

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

Здесь get все еще общедоступен (так как свойство общедоступно), но set защищен (более ограниченный спецификатор доступа).


2

Свойства используются для выставления поля. Они используют методы доступа (set, get), через которые можно читать, записывать или манипулировать значениями приватных полей.

Свойства не называют места хранения. Вместо этого у них есть средства доступа, которые читают, записывают или вычисляют свои значения.

Используя свойства, мы можем установить проверку типа данных, заданных для поля.

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

Мы можем сделать это двумя способами, используя 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()
       }
    }

Автоматически реализованное свойство Если мы не используем логику в методах get и set, мы можем использовать автоматически реализованное свойство.

При использовании автоматически реализуемых свойств компиляция создает частное анонимное поле, к которому можно получить доступ только через методы доступа get и set.

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;
     }
  }

Мы можем приватно установить свойство. В этом мы можем приватно установить свойство auto (устанавливается с помощью класса).

public int MyProperty
{
    get; private set;
}

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

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

2

В подавляющем большинстве случаев это будет имя свойства, к которому вы обращаетесь, а не имя переменной ( поле ). Причина этого заключается в том, что он считается хорошей практикой в ​​.NET и в C #, в частности, для защиты каждого фрагмента данных в классе будь то переменная экземпляра или статическая переменная (переменная класса), потому что она связана с классом.

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

Но в других случаях, таких как класс Math (пространство имен System), в класс встроено несколько статических свойств. одна из которых является математической константой PI

например. Math.PI

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.