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


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

29 853

29 ответов:

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

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
}

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

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

  • Ленивая Инициализация: если у вас есть свойство объекта, который дорого загружать, но не доступен так много в обычных запусках кода, Вы можете отложить его загрузку через свойство. Таким образом, он просто сидит там, но в первый раз, когда другой модуль пытается вызвать это свойство, он проверяет, является ли базовое поле нулевым - если это так, оно идет вперед и загружает его, неизвестный вызывающему модулю. Это может значительно ускорить инициализацию объекта.
  • Грязные Отслеживания: который я на самом деле узнал от моего вопрос здесь на 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. Свойства позволяет установить уровень доступа только для чтения

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

вот демо

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

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

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

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

когда use auto-implemented property compiles создает частное, анонимное поле, которые могут быть доступны только через методы доступа 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 (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";

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

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

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