C# автоматические свойства-почему я должен писать " get; set;"?
Если get и set являются обязательными в автоматических свойствах C#, почему мне вообще нужно указывать " get; set;"?
9 ответов
ошибка: свойство или индексатор не могут быть переданы в качестве параметра out или ref
Если вы не указать {get; set;}
тогда компилятор не будет знать, является ли это полем или свойством.
Это важно, потому что, пока они "выглядят" одинаково, компилятор относится к ним по-разному. например, вызов "InitAnInt" в свойстве вызывает ошибку.
class Test
{
public int n;
public int i { get; set; }
public void InitAnInt(out int p)
{
p = 100;
}
public Test()
{
InitAnInt(out n); // This is OK
InitAnInt(out i); // ERROR: A property or indexer may not be passed
// as an out or ref parameter
}
}
вы не должны создавать общедоступные поля / переменные в классах, вы никогда не знаете, когда вы захотите изменить его get & set accessors, и тогда вы не знаете, какой код вы собираетесь сломать, особенно если у вас есть клиенты, которые программируют против вашего API.
также у вас могут быть разные модификаторы доступа для get & set, например {get;частная set;} делает get public и The set private для объявляющего класса.
потому что вам может понадобиться свойство только для чтения:
public int Foo { get; private set; }
или свойство только для записи:
public int Foo { private get; set; }
потому что нужно каким-то образом отличить его от обычного поля.
также полезно иметь разные модификаторы доступа, например
public int MyProperty { get; private set; }
просто подумал, что поделюсь своими выводами по этой теме.
кодирование свойства, как показано ниже, является ярлыком .net 3.0"автоматически реализуемое свойство".
public int MyProperty { get; set; }
это экономит несколько нажатий на клавиши. Длинный способ объявить свойство выглядит так:
private int myProperty;
public int MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
при использовании "автоматически реализованного свойства" компилятор генерирует код для подключения get и установки в некоторое "k_BackingField". Ниже приведен разобранный код с использованием Отражатель.
public int MyProperty
{
[CompilerGenerated]
get
{
return this.<MyProperty>k__BackingField;
}
[CompilerGenerated]
set
{
this.<MyProperty>k__BackingField = value;
}
}
разобранный код C# из IL
также подключает метод для сеттера и геттера.
[CompilerGenerated]
public void set_MyProperty(int value)
{
this.<MyProperty>k__BackingField = value;
}
[CompilerGenerated]
public int get_MyProperty()
{
return this.<MyProperty>k__BackingField;
}
разобранный код C# из IL
когда вы объявляете автоматически реализованное свойство только для чтения, установив сеттер в private:
public int MyProperty { get; private set; }
все компилятор делает флаг "set " как частное лицо. Метод setter и getter говорит тот же.
public int MyProperty
{
[CompilerGenerated]
get
{
return this.<MyProperty>k__BackingField;
}
private [CompilerGenerated]
set
{
this.<MyProperty>k__BackingField = value;
}
}
разобранный код C# из IL
поэтому я не уверен, почему фреймворк требует и get; и set; на автоматически реализованном свойстве. Они могли просто не написать метод set и setter, если он не был предоставлен. Но может быть какая-то проблема уровня компилятора, которая затрудняет это, я не знаю.
если вы посмотрите на длинный способ объявления свойства только для чтения:
public int myProperty = 0;
public int MyProperty
{
get { return myProperty; }
}
а затем посмотрите на дизассемблированный код. Сеттера вообще нет.
public int Test2
{
get
{
return this._test;
}
}
public int get_Test2()
{
return this._test;
}
разобранный код C# из IL
компилятор должен знать, хотите ли вы, чтобы он генерировал геттер и/или сеттер, или, возможно, объявляет поле.
Если у свойства не было аксессоров, как компилятор отделил бы его от поля? И что отделяет его от поля?
Ну, очевидно, вам нужен способ разрешения неоднозначности между полями и свойствами. Но действительно ли необходимы ключевые слова? Например, ясно, что эти два объявления отличаются:
public int Foo;
public int Bar { }
Это может сработать. То есть, это синтаксис, компилятор мог бы понять.
но затем вы попадаете в ситуацию, когда пустой блок имеет семантическое значение. Это кажется ненадежным.
Так как никто не упоминал об этом... вы можете сделать автоматическое свойство виртуальным и переопределить его:
public virtual int Property { get; set; }
Если бы не было get / set, как бы он был переопределен? Обратите внимание, что вам разрешено переопределить геттер и сеттер не:
public override int Property { get { return int.MinValue; } }
кроме того, поскольку начиная с C# 6.0 (в Visual Studio 2015, во время этого ответа, доступного в версии Ultimate Preview), вы можете реализовать истинное свойство только для чтения:
public string Name { get; }
public string Name { get; } = "This won't change even internally";
... в отличие от в настоящее время несовершенного обходного пути с публичным геттером/частным сеттером:
public string Name { get; private set; }
public Constructor() { Name="As initialised"; }
public void Method() { Name="This might be changed internally. By mistake. Or not."; }
пример приведенного ниже (скомпилированный и исполняемый онлайн здесь).
using System;
public class Propertier {
public string ReadOnlyPlease { get; private set; }
public Propertier() { ReadOnlyPlease="As initialised"; }
public void Method() { ReadOnlyPlease="This might be changed internally"; }
public override string ToString() { return String.Format("[{0}]",ReadOnlyPlease); }
}
public class Program {
static void Main() {
Propertier p=new Propertier();
Console.WriteLine(p);
// p.ReadOnlyPlease="Changing externally!";
// Console.WriteLine(p);
// error CS0272: The property or indexer `Propertier.ReadOnlyPlease' cannot be used in this context because the set accessor is inaccessible
// That's good and intended.
// But...
p.Method();
Console.WriteLine(p);
}
}
другие вкусные новости о C# 6.0 доступны в качестве официального предварительного просмотра видео здесь.