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

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

29 ответов


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


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

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


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

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

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

так как многие из них объяснили технические плюсы и минусы Properties и Field, пришло время, чтобы попасть в примеры реального времени.

1. Properties позволяет установить уровень доступа только для чтения

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

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

Связывание Источник помогает нам уменьшить количество строк кода. Fields не принимаются BindingSource. Мы должны использовать Properties для этого.

5. Режим отладки

рассмотрим мы используем Field для хранения значения. В какой-то момент нам нужно отладить и проверить, где значение становится null для этого поля. Это будет сложно сделать там, где количество строк кода больше 1000. В таких ситуациях мы можем использовать Property и смогите установить режим отладки внутрь Property.

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

различия-использует (когда и почему)

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

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


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

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


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


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

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

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

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

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


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

например, если у меня есть переменные с именем " id "и" name", которые являются частными но может возникнуть ситуация, когда эта переменная необходима для операции чтения/записи вне класса. В этой ситуации свойство может помочь мне получить эту переменную для чтения/записи в зависимости от get / set, определенного для свойства. Ля свойство может быть readonly / writeonly / 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";
    }
}

второй вопрос здесь: "когда следует использовать поле вместо свойства?", только кратко коснулся в этот и другие ответы и и это тоже, но не очень много деталей.

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

но есть одно преимущество, которое поля имеют над свойствами, и это их способность использоваться в качестве параметров "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 метод получает, тем менее выраженным, что разница становится. Чтобы повторить это самостоятельно, запустите с первой строкой commented-out и с ней не commented-out.

даже если не было никаких преимуществ для производительности выше, есть другие места, где возможность использовать параметры ref и out может быть полезной, например, при вызове сблокированного или летучие семейство методов. Примечание: если это ново для вас, Volatile-это в основном способ получить то же поведение, что и volatile ключевое слово. Как таковой, вроде volatile, он не волшебным образом решает все проблемы безопасности потоков, как предполагает его название.

Я определенно не хочу казаться, что я выступаю за то, чтобы вы пошли "О, я должен начать выставлять поля вместо свойств."Дело в том, что если вам нужно регулярно использовать эти члены в вызовах, которые принимают параметры" ref "или" out", особенно на том, что может быть простым типом значения, который вряд ли когда-либо понадобится какой-либо из добавленных элементов свойств, можно сделать аргумент.


кроме того, свойства позволяют использовать логику при установке значения.

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

очень полезная функция.


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


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

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

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

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

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


эта страница на MSDN имеет сравнение и советы по использованию, когда:

https://msdn.microsoft.com/en-us/library/9d65as2e (v=против 90).aspx


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

  class SomeClass
  {
     int numbera; //Field

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

  }

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


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


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


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


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

где поля as-это переменные, определенные в пределах класса.


Из Википедии --


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

например, возьмем класс с именем Employee, с частными полями для имени, возраста и Employee_Id. Мы не можем получить доступ к этим полям извне класса, но мы можем получить доступ к этим частным полям через свойства.

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

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

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

  • ID не должен быть-ve.
  • имя не может быть установлено в null
  • знак пропуска должен быть прочитан только.
  • если имя студента отсутствует Имя не должно быть возвращено.

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

мой дизайн поля заключается в том, что поле должно быть изменено только его родителем, следовательно, классом. Результат переменная становится частной, затем, чтобы иметь возможность дать право читать классы / методы снаружи, я прохожу через систему свойств только с Get. Затем поле извлекается свойством и доступно только для чтения! Если вы хотите изменить его, вам нужно пройти через методы (например, конструктор), и я нахожу, что благодаря этому способу обеспечения безопасности у нас есть лучший контроль над наш код, потому что мы "фланец". Можно очень хорошо всегда публиковать все, поэтому каждый возможный случай, понятие переменных / методов /классов и т. д... на мой взгляд, это просто помощь в разработке, поддержании кода. Например, если человек возобновляет код с открытыми полями, он может сделать что угодно и поэтому вещи "нелогичные" по отношению к цели, логике, почему был написан код. Это моя точка зрения.

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

вот почему мой старый классический стиль программирования был:

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

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

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

но в других случаях вроде математический класс (System namespace), есть несколько статических свойств, которые встроены в класс. одна из которых-математическая константа ПИ

например. Математика.ПИ

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


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

пример:

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

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


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

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

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

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

мы можем сделать это двумя способами, используя геттер и сеттеры и используя свойство.

 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()
       }
    }

Auto реализовано свойство если мы не логика в get и set аксессоры мы можем использовать auto реализовано свойство.

когда uSE auto-implemented Property compiles создает частное анонимное поле к которому можно получить доступ только через GET и set accessors.

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 (set with в классе)

public int MyProperty
{
    get; private set;
}

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

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

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

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

люди попадают в sectionOne довольно легко, не было никакой проверки

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

теперь вы проверили человека и знаете, есть ли у него что-то злое с ним