Автоматические свойства C # - зачем писать get; набор;?

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


person Ben Aston    schedule 04.12.2008    source источник


Ответы (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
    }
}

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

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

person Binary Worrier    schedule 04.12.2008

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

public int Foo { get; private set; }

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

public int Foo { private get; set; }
person Brian Genisio    schedule 04.12.2008
comment
Вы также можете добавлять всевозможные модификаторы, такие как protected и т. Д. - person Tigraine; 04.12.2008
comment
Да, и что говорили другие ... вам нужен способ различать поле и свойство. - person Brian Genisio; 04.12.2008
comment
Небольшое примечание: существует концепция полей только для чтения. Фреймворк позаботится о том, чтобы они были написаны только один раз. Он отличается от частных сеттеров или геттеров, которые могут быть написаны, если у вас есть доступ. - person Cristian Libardo; 04.12.2008
comment
Также см. Мой ответ, речь идет не только об уровнях доступа, компилятор по-разному обрабатывает поля и свойства. - person Binary Worrier; 04.12.2008
comment
Да, я согласен. Смотрите мой комментарий (третий внизу) - person Brian Genisio; 04.12.2008
comment
изменил выбранный ответ, потому что более поздний комментарий более полно отвечает на вопрос - person Ben Aston; 04.12.2008
comment
@cristianlibardo: ключевое слово readonly (похоже, то, о чем вы говорите) отличается от свойства только для чтения. - person Scott Dorman; 04.12.2008
comment
@CristianLibardo: поля только для чтения можно записывать сколько угодно раз, но это можно записывать только на этапе построения. (То есть в ctor или в инициализаторе переменной.) - person Arjan Einbu; 15.01.2009
comment
@BrianGenisio Эти свойства на самом деле не только для чтения, а скорее с частным доступом для записи, которые до сих пор были достаточно близки, однако в C # 6.0 (Visual Studio 2015) у нас есть реальные свойства только для чтения (как ответили здесь). Ура! - person Robert Synoradzki; 05.12.2014
comment
@ensisNoctis Достаточно честно! Он доступен только для чтения из общедоступного интерфейса, но вы правы, он не является неизменным. - person Brian Genisio; 10.12.2014

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

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

public int MyProperty { get; set; }

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

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

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

Все, что компилятор делает, помечает "набор" как частный. То же самое говорят методы установки и получения.

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

дизассемблированный код C # из 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;
}

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

person Ron Todosichuk    schedule 04.12.2008
comment
Метод частного набора требуется с автоматическими свойствами, потому что в противном случае вы никогда не сможете установить значение для чего-либо, что было бы бессмысленно. Вы можете исключить сеттер из неавтоматического свойства, потому что резервное поле предоставляет способ изменить значение внутри. - person Jeromy Irvine; 04.12.2008
comment
Хорошая мысль, это правильно. Поскольку у вас нет частной переменной, при использовании автоматически реализуемого свойства вы знаете, как установить значение, если его там не было. - person Ron Todosichuk; 04.12.2008

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

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

public int MyProperty { get; private set; }
person Cristian Libardo    schedule 04.12.2008
comment
Но публичные поля бесполезны. - person Daniel Earwicker; 04.12.2008
comment
Согласованный. Синтаксис, вероятно, можно частично объяснить тем, что господин Андер не хочет вводить новое ключевое слово в языке. - person Cristian Libardo; 04.12.2008
comment
Эрвикер: Я нашел общедоступные поля полезными в моем классе Vector2f - они сильно ускорили программу (по сравнению со свойствами), а класс достаточно прост, и мне никогда не придется менять реализацию. - person Stefan Monov; 14.01.2010

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

person Kris    schedule 04.12.2008

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

person Rune Grimstad    schedule 04.12.2008

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

public int Foo;
public int Bar { }

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

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

person Robert Rossney    schedule 04.12.2008

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

public virtual int Property { get; set; }

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

public override int Property { get { return int.MinValue; } }
person Zaid Masud    schedule 30.09.2012

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

person Robert Synoradzki    schedule 04.12.2014