В чем разница между полем и свойством? - PullRequest
971 голосов
/ 17 ноября 2008

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

Ответы [ 30 ]

854 голосов
/ 17 ноября 2008

Свойства выставляют поля. Поля должны (почти всегда) быть приватными для класса и доступны через свойства 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;} 
}

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

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

233 голосов
/ 17 ноября 2008

Принципы объектно-ориентированного программирования говорят о том, что внутренняя работа класса должна быть скрыта от внешнего мира. Если вы выставляете поле, вы, по сути, выставляете внутреннюю реализацию класса. Поэтому мы заключаем поля в свойства (или методы в случае 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
}
147 голосов
/ 17 ноября 2008

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

91 голосов
/ 17 ноября 2008

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

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

Используя Свойства, вы можете генерировать событие, когда значение свойства изменяется (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(){
   EventHandler localEvent = NameChanging;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }

 private void OnNameChanged(){
   EventHandler localEvent = NameChanged;
   if (localEvent != null) {
     localEvent(this,EventArgs.Empty);
   }
 }
}
42 голосов
/ 06 октября 2014

Поскольку многие из них объяснили техническими плюсами и минусами 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;
        }
   }
28 голосов
/ 12 сентября 2013

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

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

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

10 голосов
/ 17 ноября 2008

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

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

8 голосов
/ 17 ноября 2008

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

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

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

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

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

8 голосов
/ 17 ноября 2008

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

...