C # Автоматические свойства - Почему я должен написать "get; set;"? - PullRequest
43 голосов
/ 04 декабря 2008

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

Ответы [ 9 ]

63 голосов
/ 04 декабря 2008

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

public int Foo { get; private set; }

Или свойство только для записи:

public int Foo { private get; set; }
51 голосов
/ 04 декабря 2008

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

Также вы можете иметь различные модификаторы доступа для get & set, например {получить; private set;} делает get общедоступным, а set - приватным для объявленного класса.

16 голосов
/ 04 декабря 2008

Просто подумал, что поделюсь своими выводами на эту тему.

Кодирование свойства, подобного следующему, - это быстрый вызов .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;
    }
}

дизассемблированный код 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 " как private. Методы установки и получения говорят одинаково.

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

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

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

16 голосов
/ 04 декабря 2008

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

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

public int MyProperty { get; private set; }
4 голосов
/ 04 декабря 2008

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

2 голосов
/ 04 декабря 2014

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

2 голосов
/ 30 сентября 2012

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

public virtual int Property { get; set; }

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

public override int Property { get { return int.MinValue; } }
2 голосов
/ 05 декабря 2008

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

public int Foo;
public int Bar { }

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

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

2 голосов
/ 04 декабря 2008

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

...