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 доступны в качестве официального предварительного просмотра видео здесь.