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

97

Я создал автоматизированное свойство:

public int Foo { get; } 

Это только геттер. Но когда я создаю конструктор, я могу изменить значение:

public MyClass(string name)
{
    Foo = 5;
}

Почему это возможно, даже если это только получение?

Ноам Б.
источник
На самом деле он не использует сеттер (потому что у него его нет). Он напрямую устанавливает базовое поле (которое скрыто от нас, поэтому вам нужно использовать имя свойства)
Dennis_E
14
Какая польза свойство, если оно не может никогда быть инициализированы / комплект? Якуб Массад ответил идеально
Vikhram

Ответы:

123

Это новая функция C # 6, «автоматические свойства только для получения», также известная как «инициализаторы автоматических свойств для свойств только для чтения», как описано в статье журнала MSDN «C #: новый и улучшенный C # 6.0» от Марка Михаэлиса и в проекте спецификации языка C # 6.0 .

Установщик поля только для чтения доступен только в конструкторе, во всех других сценариях поле по-прежнему доступно только для чтения и ведет себя как раньше.

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

Эта функция считалась такой же важной, поскольку с момента появления автоматически реализуемых свойств в C # 3 изменяемые свойства (те, которые имеют геттер и сеттер) стали писать быстрее, чем неизменяемые (те, у которых есть только геттер), то есть люди соблазн использовать изменяемые свойства, чтобы избежать необходимости вводить код для резервного поля, обычно необходимого для свойств только для чтения. Подробнее об автоматически реализуемых свойствах можно прочитать в соответствующем разделе Руководства по программированию Microsoft C # .

В этом сообщении в блоге Шона Секстона «# 1207 - C # 6.0 - Автоматические инициализаторы свойств для свойств, доступных только для чтения» есть хорошее объяснение и следующий пример:

До C # 6.0, если вам нужно свойство, доступное только для чтения (неизменяемое), вы обычно использовали бы поддерживающее поле только для чтения, которое инициализируется в конструкторе, как показано ниже.

public class Dog 
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    private readonly DateTime creTime;
    public DateTime DogCreationTime 
    {
        get { return creTime; }
    }

    public Dog(string name)
    {
        Name = name;
        creTime = DateTime.Now;
    }
}

В C # 6.0 вы можете использовать автоматически реализуемые свойства для реализации свойства, доступного только для чтения. Вы делаете это с помощью инициализатора автоматического свойства. Результат намного чище, чем в приведенном выше примере, где нам пришлось явно объявить поддерживающее поле.

public class Dog
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    public DateTime DogCreationTime { get; } = DateTime.Now;

    public Dog(string name)
    {
        Name = name;
    }
}

Более подробную информацию также можно найти в репозитории dotnet Roslyn на GitHub :

Автоматические свойства теперь можно объявлять без установщика.

Поле поддержки авто-свойства только для получения неявно объявляется как доступное только для чтения (хотя это имеет значение только для целей отражения). Его можно инициализировать с помощью инициализатора свойства, как в примере выше. Кроме того, свойство только для получения может быть назначено в теле конструктора объявляющего типа, что приводит к присвоению значения непосредственно базовому полю:

Речь идет о более кратком выражении типов, но обратите внимание, что это также устраняет важную разницу в языке между изменяемыми и неизменяемыми типами: автоматические свойства были сокращением, доступным только в том случае, если вы были готовы сделать свой класс изменяемым, и поэтому соблазн использовать по умолчанию чтобы это было здорово. Теперь, благодаря автоматическим свойствам только для получателей, игровое поле выровнялось между изменяемым и неизменным.

и в проекте спецификации языка C # 6.0 (NB: спецификация языка является окончательной для Microsoft, но еще не утверждена в качестве стандарта EMCA / ISO , отсюда и «черновик»):

Автоматически реализованные свойства

Автоматически реализуемое свойство (или для краткости auto-свойство) - это неабстрактное не-внешнее свойство с телами доступа только с точкой с запятой. Авто-свойства должны иметь метод доступа get и, при необходимости, могут иметь метод доступа set.

Когда свойство указано как автоматически реализуемое свойство, для свойства автоматически доступно скрытое резервное поле, а средства доступа реализованы для чтения и записи в это резервное поле. Если автоматическое свойство не имеет установленного средства доступа, резервное поле считается доступным только для чтения (поля только для чтения). Так же, как поле только для чтения, авто-свойство только для получения также может быть назначено в теле конструктора включающего класса. Такое назначение присваивается непосредственно поддерживающему полю свойства только для чтения.

Автоматическое свойство может дополнительно иметь property_initializer, который применяется непосредственно к резервному полю как variable_initializer (инициализаторы переменных).

TomRedox
источник
1
Это глупый дизайн. Это должно быть ошибкой времени компиляции, если установлено в месте, где свойство считается доступным только для чтения.
Шив
Странность для меня заключается в том, что компилятор все еще сообщает об ошибке CS0200 C# Property or indexer cannot be assigned to -- it is read onlyпри использовании обычного свойства. Считаются ли "автоматические свойства только для получения" доступными только для чтения или нет?
Кайл Делани
24

Это новая функция в C # 6, которая позволяет создавать свойства, доступные только для чтения, и инициализировать их значения из конструктора (или встроенного, когда вы их объявляете).

Если вы попытаетесь изменить значение этого свойства вне конструктора, это приведет к ошибке компиляции.

Он доступен только для чтения в том смысле, что после инициализации его значения (встроенного или внутри конструктора) вы не можете изменить его значение.

Якуб Массад
источник
Итак, какое объяснение? Какое определение для геттера?
Ноам Б.
16

Если бы невозможно было инициализировать свойство только для чтения из конструктора (или инициализатора автоматического свойства), тогда это было бы бесполезно, поскольку оно всегда возвращало бы значение по умолчанию для своего типа (0 для числовых, null для ссылочных типов ). Та же семантика применяется к полям только для чтения во всех версиях C #.

Чтобы определить истинное свойство, предназначенное только для получения (которое не может быть инициализировано из конструктора), вам необходимо указать, что оно возвращает, как часть определения:

public int Foo { get { return 5; } }

Или, более кратко, на C # 6:

public int Foo => 5;
Дуглас
источник
Не совсем верно, свойства только для чтения очень полезны для инкапсуляции некоторых условий в вашем коде. Вы можете написать оператор if и практически любой код для оценки других свойств или условий и возврата соответствующего значения каждый раз, когда вы читаете свойство
sebagomez
3
@sebagomez: Я не уверен, что понимаю вашу точку зрения - разве я не это продемонстрировал в своем примере?
Дуглас
5

"Автоматически реализованные свойства только для чтения"

Прежде всего хочу уточнить, что недвижимость нравится

public string FirstName { get; }

Известны как «автоматически реализуемые свойства только для чтения».

Чтобы проверить это, вы можете запустить и проверить приведенный выше код с помощью Visual Studio. Если вы измените версию языка с C # 6.0 на C # 5.0, компилятор выдаст следующее исключение. Функция «автоматически реализованные свойства только для чтения» недоступна в C # 5. Используйте версию языка 6 или выше.

чтобы изменить языковую версию C #, посетите здесь

Теперь я перехожу к вашему второму вопросу

«Это только геттер. Но когда я создаю конструктор, я могу изменить значение »

Microsoft вводит «автоматически реализуемые свойства только для чтения» в логике только для чтения. Как мы знаем, ключевое слово «только для чтения» доступно в C # 1.0. мы используем «только для чтения» ключевое слово в качестве модификатора на поле и это поле может быть назначено 2 способами либо в момент декларации или в конструкторе в том же классе.

Таким же образом значение «автоматически реализуемых свойств только для чтения» может быть присвоено двумя способами.

Way1 (на момент объявления):

public string FirstName { get; } = "Banketeshvar";

Way2 (в конструкторе того же класса)

Person()
{
 FirstName  = "Banketeshvar";
}

Собственность только для чтения

Если вы ищете недвижимость исключительно для чтения, тогда выбирайте это

public string FullName => "Manish Sharma";

теперь вы не можете присвоить значение свойства «FullName» из конструктора. Если вы попытаетесь это сделать, он выдаст следующие исключения

«Свойство или индексатор 'Person.FullName' нельзя присвоить - он доступен только для чтения»

Банкетешвар Нараян
источник
2
обратите внимание, что FullName => "foo bar" будет оцениваться КАЖДЫЙ РАЗ.
juFo
4

Функция автоматического свойства была добавлена ​​в язык во время выпуска C # 3.0. Это позволяет вам определять свойство без какого-либо резервного поля, однако вам все равно нужно использовать конструктор для инициализации этих автоматических свойств значением, отличным от значения по умолчанию. В C # 6.0 представлена ​​новая функция, называемая автоматическим инициализатором свойств, которая позволяет инициализировать эти свойства без конструктора, как показано ниже:

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

public class MyClass
{
    public int Foo { get; }

    public Foo(int foo)
    {
        Foo = foo;
    }
}

Теперь в C # 6.0 возможность использовать инициализатор со свойством auto означает, что явный код конструктора не требуется.

public string Foo { get; } = "SomeString";

public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };

Вы можете найти больше информации об этом здесь

Рахул Никате
источник
1

Объявленная переменная readonlyможет быть записана в конструкторе, но в языках, которые поддерживают атрибут, не может быть изменена после возврата конструктора. Этот квалификатор был предоставлен как языковая функция, потому что он часто необходим для полей, значения которых будут варьироваться в зависимости от параметров конструктора (то есть они не могут быть инициализированы до запуска конструктора), но не должны изменяться после возврата конструктора, но это было может использоваться только для переменных, представленных как поля. Семантикаreadonly-qualified fields would in many cases have been perfect for public members except that it's often better for classes to expose members--even immutable ones--as properties rather than fields.

Подобно тому, как существуют автоматические свойства для чтения и записи, позволяющие классам предоставлять изменяемые свойства так же легко, как и обычные поля, существуют автоматические свойства только для чтения, позволяющие классам предоставлять неизменяемые свойства так же легко, как и readonlyквалифицированные поля. Точно так же, как readonlyполя с квалификацией могут быть записаны в конструкторе, также можно использовать свойства только для получения.

суперкар
источник