В чем разница между полем и свойством?
Что в C# отличает поле от свойства и когда следует использовать поле вместо свойства?
34 ответа
Свойства выставляют поля. Поля должны (почти всегда) быть приватными для класса и доступны через свойства 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
}
Важным отличием является то, что интерфейсы могут иметь свойства, но не поля. Для меня это подчеркивает, что свойства должны использоваться для определения открытого интерфейса класса, в то время как поля предназначены для использования в частной, внутренней работе класса. Как правило, я редко создаю открытые поля и так же редко создаю непубличные свойства.
Я дам вам несколько примеров использования свойств, которые могут привести к вращению шестерен:
- Ленивая инициализация: если у вас есть свойство объекта, которое дорого загружать, но к которому обычно не обращаются при обычных запусках кода, вы можете отложить его загрузку через свойство. Таким образом, он просто сидит там, но в первый раз, когда другой модуль пытается вызвать это свойство, он проверяет, является ли нижележащее поле пустым - если оно есть, он идет вперед и загружает его, неизвестно вызывающему модулю. Это может значительно ускорить инициализацию объекта.
- Грязное отслеживание: о чем я действительно узнал из своего собственного вопроса здесь, на Stackru. Когда у меня много объектов, значения которых могли измениться во время выполнения, я могу использовать это свойство, чтобы отслеживать, нужно ли их сохранять обратно в базу данных или нет. Если ни одно свойство объекта не изменилось, флаг IsDirty не сработает, и, следовательно, функция сохранения пропустит его при принятии решения о том, что необходимо вернуть в базу данных.
Используя Свойства, вы можете генерировать событие, когда значение свойства изменяется (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);
}
}
}
Поскольку многие из них объяснили с техническими плюсами и минусами 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;
}
}
ОТЛИЧИЯ - ИСПОЛЬЗОВАНИЕ (когда и почему)
Поле - это переменная, которая объявлена непосредственно в классе или структуре. У класса или структуры могут быть поля экземпляра или статические поля, или оба. Как правило, вы должны использовать поля только для переменных, которые имеют частную или защищенную доступность. Данные, которые ваш класс предоставляет клиентскому коду, должны предоставляться через методы, свойства и индексаторы. Используя эти конструкции для косвенного доступа к внутренним полям, вы можете защититься от неверных входных значений.
Свойство - это член, который предоставляет гибкий механизм для чтения, записи или вычисления значения частного поля. Свойства можно использовать так, как будто они являются открытыми членами данных, но на самом деле это специальные методы, называемые методами доступа. Это позволяет легко получать доступ к данным, а также способствует безопасности и гибкости методов. Свойства позволяют классу предоставлять общедоступный способ получения и установки значений, скрывая при этом код реализации или проверки. Метод доступа к свойству get используется для возврата значения свойства, а метод доступа к set используется для назначения нового значения.
Хотя поля и свойства выглядят похожими друг на друга, это два совершенно разных языковых элемента.
Поля - единственный механизм для хранения данных на уровне класса. Поля концептуально являются переменными в области класса. Если вы хотите сохранить некоторые данные в экземплярах ваших классов (объектов), вам необходимо использовать поля. Другого выбора нет. Свойства не могут хранить какие-либо данные, хотя может показаться, что они могут это делать. Смотрите ниже.
С другой стороны, свойства никогда не хранят данные. Это просто пары методов (get и set), которые могут вызываться синтаксически аналогично полям, и в большинстве случаев они обращаются (для чтения или записи) к полям, что является источником некоторой путаницы. Но поскольку методы свойств являются (с некоторыми ограничениями, такими как фиксированный прототип) обычными методами C#, они могут делать то же, что и обычные методы. Это означает, что у них может быть 1000 строк кода, они могут генерировать исключения, вызывать другие методы, могут быть даже виртуальными, абстрактными или переопределенными. Что делает свойства особенными, так это то, что компилятор C# хранит некоторые дополнительные метаданные в сборках, которые можно использовать для поиска определенных свойств - широко используемой функции.
Методы получения и установки свойств имеют следующие прототипы.
PROPERTY_TYPE get();
void set(PROPERTY_TYPE value);
Это означает, что свойства можно "эмулировать" путем определения поля и двух соответствующих методов.
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).
Хотя методы свойств могут делать что угодно, в большинстве случаев они служат способом доступа к полям объектов. Если вы хотите сделать поле доступным для других классов, вы можете сделать это двумя способами.
- Делать поля общедоступными - не рекомендуется.
- Использование свойств.
Вот класс, использующий общедоступные поля.
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());
}
}
}
Обновленная версия класса имеет следующие преимущества.
FullName
а такжеYearOfBirth
проверяются на недопустимые значения.Age
не записывается. Это рассчитано изYearOfBirth
и текущий год.- Новая недвижимость
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;
}
}
}
Итак, как видите, компилятор по-прежнему использует поля для хранения значений, поскольку поля - это единственный способ сохранить значения в объектах.
Как видите, хотя свойства и поля имеют схожий синтаксис использования, это очень разные концепции. Даже если вы используете автоматические свойства или события - скрытые поля генерируются компилятором, где хранятся реальные данные.
Если вам нужно сделать значение поля доступным для внешнего мира (пользователей вашего класса), не используйте общедоступные или защищенные поля. Поля всегда должны быть помечены как частные. Свойства позволяют выполнять проверки значений, форматирование, преобразование и т. Д. И в целом делают код более безопасным, читаемым и расширяемым для будущих модификаций.
Свойства имеют основное преимущество, позволяя вам изменять способ доступа к данным на объекте, не нарушая его общедоступного интерфейса. Например, если вам нужно добавить дополнительную проверку или преобразовать сохраненное поле в вычисляемое, вы можете сделать это легко, если вы изначально выставили поле как свойство. Если вы только что выставили поле напрямую, вам придется изменить открытый интерфейс вашего класса, чтобы добавить новую функциональность. Это изменение повредит существующие клиенты, что потребует их перекомпиляции, прежде чем они смогут использовать новую версию вашего кода.
Если вы пишете библиотеку классов, предназначенную для широкого потребления (например,.NET Framework, которой пользуются миллионы людей), это может стать проблемой. Однако, если вы пишете класс, используемый внутри небольшой базы кода (скажем, <= 50 тыс. Строк), это на самом деле не имеет большого значения, потому что ваши изменения ни на кого не повлияют. В этом случае это действительно сводится к личным предпочтениям.
Свойства поддерживают асимметричный доступ, то есть вы можете иметь либо геттер и сеттер, либо только один из двух. Точно так же свойства поддерживают индивидуальную доступность для getter / setter. Поля всегда симметричны, то есть вы всегда можете получить и установить значение. Исключением являются поля только для чтения, которые, очевидно, не могут быть установлены после инициализации.
Свойства могут работать очень долго, иметь побочные эффекты и даже могут генерировать исключения. Поля быстрые, без побочных эффектов и никогда не будут генерировать исключения. Из-за побочных эффектов свойство может возвращать разные значения для каждого вызова (как в случае DateTime.Now, т. Е. DateTime.Now не всегда равен DateTime.Now). Поля всегда возвращают одно и то же значение.
Поля могут использоваться для параметров out / ref, свойства - нет. Свойства поддерживают дополнительную логику - это может использоваться для реализации отложенной загрузки среди прочего.
Свойства поддерживают уровень абстракции, инкапсулируя все, что это означает, чтобы получить / установить значение.
Используйте свойства в большинстве случаев, но старайтесь избегать побочных эффектов.
В фоновом режиме свойство компилируется в методы. Так что Name
свойство компилируется в get_Name()
а также set_Name(string value)
, Вы можете увидеть это, если изучите скомпилированный код. Таким образом, при их использовании возникают (очень) небольшие потери производительности. Обычно вы всегда будете использовать свойство, если вы выставляете поле снаружи, и вы часто будете использовать его внутри, если вам нужно проверить значение.
Второй вопрос здесь, "когда следует использовать поле вместо свойства?", Только вкратце затронут в этом другом ответе и вроде как и этот, но не очень подробно.
В общем, все остальные ответы на тему хорошего дизайна: предпочитайте выставлять свойства, а не выставлять поля. Хотя вы, вероятно, не будете регулярно говорить: "Ух ты, представь, насколько хуже будет, если бы я сделал это полем вместо свойства", гораздо реже можно подумать о ситуации, когда ты скажешь "Ух ты, слава богу, я использовал здесь поле вместо собственности ".
Но есть одно преимущество, которое поля имеют над свойствами, и это их способность использоваться в качестве параметров "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", особенно для чего-то, что может быть простым типом значения, которому вряд ли когда-либо понадобится какой-либо из элементов свойств с добавленной стоимостью, аргумент может быть сделан.
Если вы хотите, чтобы ваша личная переменная (поле) была доступна для объекта вашего класса из других классов, вам нужно создать свойства для этих переменных.
например, если у меня есть переменные с именами "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";
}
}
Технически, я не думаю, что есть разница, потому что свойства - это просто обертки вокруг полей, созданных пользователем или автоматически созданных компилятором. Цель свойств - обеспечить инкапсуляцию и предложить облегченную функцию, похожую на метод. Это просто плохая практика объявлять поля как общедоступные, но у них нет проблем.
Поля - это обычные переменные-члены или экземпляры класса. Свойства являются абстракцией для получения и установки своих значений. Свойства также называются средствами доступа, потому что они предлагают способ изменить и извлечь поле, если вы выставите поле в классе как личное. Как правило, вы должны объявить свои переменные-члены частными, а затем объявить или определить свойства для них.
class SomeClass
{
int numbera; //Field
//Property
public static int numbera { get; set;}
}
Кроме того, свойства позволяют использовать логику при настройке значений.
Таким образом, вы можете сказать, что хотите установить значение только в целочисленное поле, если значение больше x, в противном случае выдается исключение.
Действительно полезная функция.
(Это действительно должен быть комментарий, но я не могу оставить комментарий, поэтому, пожалуйста, извините, если он не подходит как сообщение).
Однажды я работал в месте, где рекомендуемой практикой было использование открытых полей вместо свойств, когда эквивалентное свойство def просто обращалось к полю, как в:
get { return _afield; }
set { _afield = value; }
Их аргументация заключалась в том, что публичное поле может быть преобразовано в собственность позже в будущем, если потребуется. В то время мне это показалось немного странным. Судя по этим постам, похоже, что не многие здесь согласятся. Что вы могли бы сказать, чтобы попытаться что-то изменить?
Редактировать: я должен добавить, что вся база кода в этом месте была скомпилирована одновременно, поэтому они могли подумать, что изменение открытого интерфейса классов (путем изменения открытого поля на свойство) не было проблемой.
Мой дизайн поля состоит в том, что поле должно быть изменено только его родителем, следовательно, классом. В результате переменная становится приватной, чтобы иметь возможность дать право читать классы / методы за пределами, я прохожу через систему свойств только с 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;
}
}
Основное и общее различие:
Поля
- ВСЕГДА предоставляйте доступ как для получения, так и для установки
- НЕ МОЖЕТ вызывать побочные эффекты (генерирование исключений, вызов методов, изменение полей, кроме того, которое было получено / установлено и т. Д.)
Свойства
- НЕ ВСЕГДА предоставляйте доступ и get, и set
- МОЖЕТ вызывать побочные эффекты
Если вы собираетесь использовать потоковые примитивы, вы вынуждены использовать поля. Свойства могут сломать ваш многопоточный код. Кроме того, то, что сказал Кори, правильно.
Из Википедии - Объектно-ориентированное программирование:
Объектно-ориентированное программирование (ООП) - это парадигма программирования, основанная на концепции "объектов", которые представляют собой структуры данных, которые содержат данные в форме полей, часто называемых атрибутами; и код в форме процедур, часто называемых методами. (выделение добавлено)
Свойства на самом деле являются частью поведения объекта, но предназначены для того, чтобы предоставить потребителям объекта иллюзию / абстракцию работы с данными объекта.
Свойства инкапсулируют поля, что позволяет вам выполнять дополнительную обработку значения, которое будет установлено или получено. Обычно излишне использовать свойства, если вы не будете выполнять предварительную или постобработку значения поля.
Традиционно закрытые поля устанавливаются через методы получения и установки. Ради меньшего количества кода вы можете использовать свойства для установки полей.
IMO, Properties - это просто пары функций / методов / интерфейсов "SetXXX()" "GetXXX()", которые мы использовали ранее, но они более лаконичны и элегантны.
Дополнительная информация: По умолчанию методы доступа get и set доступны так же, как и само свойство. Вы можете контролировать / ограничивать доступность доступа по отдельности (для получения и установки), применяя к ним более ограничивающие модификаторы доступа.
Пример:
public string Name
{
get
{
return name;
}
protected set
{
name = value;
}
}
Здесь get все еще общедоступен (так как свойство общедоступно), но set защищен (более ограниченный спецификатор доступа).
Подумайте об этом: у вас есть комната и дверь, чтобы войти в эту комнату. Если вы хотите проверить, как кто входит и обезопасить вашу комнату, то вы должны использовать свойства, иначе они не будут никакой дверью, и каждый легко войдет без каких-либо правил.
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";
Теперь вы проверили человека и знаете, есть ли у него что-то плохое с ним
Свойства - это особый вид члена класса. В свойствах мы используем предопределенный метод 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;
}
}
Поля - это переменные в классах. Поля - это данные, которые вы можете инкапсулировать с помощью модификаторов доступа.
Свойства похожи на поля в том, что они определяют состояния и данные, связанные с объектом.
В отличие от поля свойство имеет специальный синтаксис, который контролирует, как человек читает данные и записывает данные, они известны как операторы get и set. Заданная логика часто может использоваться для проверки.
Свойства используются для выставления поля. Они используют методы доступа (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; }
}
Когда у вас есть класс, который "Автомобиль". Свойства цвета, формы..
Где поля - это переменные, определенные в области видимости класса.