Разница в C # между различными стилями геттера

154

Я иногда вижу сокращения в свойствах для геттера. Например, эти два типа:

public int Number { get; } = 0

public int Number => 0;

Может кто-нибудь сказать, пожалуйста, есть ли различия между этими двумя. Как они себя ведут? Оба они доступны только для чтения?

WoIIe
источник

Ответы:

266

Да, оба они доступны только для чтения, но есть разница. В первом есть вспомогательное поле, которое инициализируется 0, прежде чем конструктор будет выполнен. Вы можете изменить значение только в конструкторе , как обычное поле только для чтения. Сам геттер просто возвращает значение поля.

Во втором случае геттер просто возвращает 0 каждый раз, без поля.

Поэтому, чтобы вообще не использовать какие-либо автоматически реализованные свойства или члены с выражениями, мы имеем:

Первая версия

private readonly int _number = 0;
public int Number { get { return _number; } }

Вторая версия

public int Number { get { return 0; } }

Более ясный пример разницы можно увидеть так:

public DateTime CreationTime { get; } = DateTime.UtcNow;
public DateTime CurrentTime => DateTime.UtcNow;

Если вы создаете один объект, его CreationTimeсвойство всегда будет давать один и тот же результат - потому что он хранится в поле только для чтения, инициализированном при построении объекта. Однако каждый раз, когда вы получаете доступ к CurrentTimeсвойству, это будет вызывать DateTime.UtcNowоценку, поэтому вы получите потенциально другой результат.

Джон Скит
источник
23
Обратите внимание, что вторая версия не всегда возвращает одно и то же значение. Один хороший пример, если вы вернетесь random.NextInt(). Первая версия оценит это один раз и всегда будет иметь одинаковое значение. Второй будет возвращать новое значение каждый раз.
248

Разница лишь в том, когда это 0оценивается: при создании объекта или при использовании свойства.

Вы можете увидеть это лучше с помощью свойств DateTime:

class SomeTestClass
{
    public DateTime Start { get; } = DateTime.Now;

    public DateTime Now => DateTime.Now;
}

StartСвойство постоянно возвращается в то же время (в момент создания экземпляра), в то время как Nowизменения , чтобы отразить текущее время.

Пояснение :

Первая версия («Пуск») предоставляет начальное значение, которое может даже быть перезаписано конструктором. Так что это оценивается только один раз.
Вторая версия («Сейчас») предоставляет выражение, которое будет «получателем» этого свойства. Так что это оценивается каждый раз, когда свойство читается. Нет даже вспомогательного поля, которое конструктор может перезаписать.

Ханс Кеинг
источник
26
Это самое важное различие, я думаю.
Мэтью
14
Принятый ответ наиболее точно определяет разницу в примере кода, но это объясняет более полезную разницу в двух структурах.
Камил Дракари
3
Вау, ты получил больше голосов, чем сам знаменитый Джон Скит.
machine_1
21

Это особенности языка C # 6.

Первый пример

public int Number { get; } = 0

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

Второй пример

public int Number => 0;

И второй пример - тела выражений для членов функций, подобных свойствам . Обратите внимание, что здесь нет никакого getключевого слова: оно подразумевается использованием синтаксиса тела выражения.

Оба доступны только для чтения.

Jehof
источник
5
... но, как объясняет Джон Скит, вы можете изменить значение, возвращаемое первым.
Мартин Боннер поддерживает Монику
2
@MartinBonner ... но только в конструкторе.
Деннис Кайперс
5
или, как всегда, через размышления (незначительные придирки)
Marco Mp