С# Автоматические свойства - зачем мне писать "get; set;"?

Если оба метода get и set являются обязательными в автоматических свойствах С#, почему я должен беспокоиться о том, чтобы указать "get; set;" на всех?

Ответ 1

ОШИБКА: свойство или индекс не могут быть переданы как параметр 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
    }
}

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

Также вы можете иметь разные модификаторы доступа для get и set, например. {получить; закрытый набор;} делает публикацию public и набор закрытым для класса объявления.

Ответ 2

Поскольку вам может понадобиться свойство только для чтения:

public int Foo { get; private set; }

Или свойство Write-only:

public int Foo { private get; set; }

Ответ 3

Потому что вам нужно каким-то образом отличить его от простых полей.

Также полезно иметь разные модификаторы доступа, например.

public int MyProperty { get; private set; }

Ответ 4

Просто подумал, что поделился бы своими выводами по этой теме.

Кодирование свойства, подобного следующему, представляет собой ярлык .net 3.0 " автоматически реализованное свойство".

public int MyProperty { get; set; }

Это экономит вас при наборе текста. Длинный способ объявления свойства выглядит следующим образом:

private int myProperty;
public int MyProperty 
{
  get { return myProperty; }
  set { myProperty = value; } 
}

Когда вы используете "автоматически реализованное свойство", компилятор генерирует код для подключения get и устанавливается на некоторый "k_BackingField". Ниже представлен дизассемблированный код с использованием Reflector.

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

дизассемблированный код С# из IL

Также подключает метод для установщика и получателя.

[CompilerGenerated]
public void set_MyProperty(int value)
{
    this.<MyProperty>k__BackingField = value;
}
[CompilerGenerated]
public int get_MyProperty()
{
    return this.<MyProperty>k__BackingField;
}

дизассемблированный код С# из IL

Когда вы объявляете только автообновляемое свойство read only, установив приватный параметр setter:

 public int MyProperty { get; private set; }

Все компиляторы делают флаг установлен закрытым. Метод setter и getter говорит то же самое.

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    private [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

дизассемблированный код С# из IL

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

дизассемблированный код С# из IL

Ответ 5

Компилятор должен знать, хотите ли вы, чтобы он генерировал getter и/или сеттер, или, возможно, объявлял поле.

Ответ 6

Если у объекта не было доступа, каким образом компилятор отделит его от поля? И что бы отделить его от поля?

Ответ 7

Ну, очевидно, вам нужен способ устранения неоднозначности полей и свойств. Но требуются ли ключевые слова действительно необходимые? Например, ясно, что эти два объявления различны:

public int Foo;
public int Bar { }

Это может сработать. То есть, это синтаксис, который мог бы понять компилятор.

Но тогда вы попадаете в ситуацию, когда пустой блок имеет смысловое значение. Это кажется неустойчивым.

Ответ 8

Поскольку никто не упомянул об этом... вы могли бы сделать авто-свойство виртуальным и переопределить его:

public virtual int Property { get; set; }

Если бы не было get/set, как бы это было переопределено? Обратите внимание, что вам разрешено переопределить получателя, а не установщика:

public override int Property { get { return int.MinValue; } }

Ответ 9

Кроме того, поскольку С# 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 good and intended.

        // But...
        p.Method();
        Console.WriteLine(p);
    }
}

Другие вкусные новости о С# 6.0 доступны в качестве официального предварительного просмотра здесь.