Есть ли способ сделать автоматические свойства только для чтения (а не только частными)?

Автоматические свойства позволяют мне заменить этот код:

private MyType myProperty;
public MyType MyProperty
{
    get { return myPropertyField; }
}

с этим кодом:

public MyType MyProperty { get; private set; }

с некоторыми изменениями здесь и там - но есть ли способ заменить этот код:

private readonly MyType myProperty;
public MyType MyProperty
{
    get { return myPropertyField; }
}

с чем-то похожим?


person Simon    schedule 08.10.2009    source источник
comment
Некоторое время назад я сам искал это (я надеялся, что что-то вроде public readonly MyType MyProperty { get; private set; } сработает), но в итоге я использовал синтаксис в конце вашего вопроса.   -  person Blixt    schedule 08.10.2009


Ответы (6)


Нет, но эта идея отслеживается в Connect.

person Mark Seemann    schedule 08.10.2009

Действительно, в настоящее время это невозможно сделать.

Мы понимаем, что в C # 3 мы создали некоторый философский оксюморон. Дизайн LINQ в значительной степени пропитан традиционным неизменяемым функциональным стилем программирования - выполнение откладывается, запросы представлены неизменяемыми монадами, деревья выражений неизменны и т. Д.

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

Однако, поскольку мы все большие поклонники неизменного стиля программирования и верим, что этот стиль принесет дивиденды, упростив обеспечение корректности многопоточных приложений в будущих повсеместных многоядерных архитектурах, мы определенно заинтересованы в поисках способа обуздать введенную нами изменчивость. Автозаполнение только для чтения - один из очевидных способов сделать это; маленький шаг, но хороший.

Тем не менее, мы еще даже не выпустили C # 4 и не объявили, что после этого появятся какие-либо новые языковые функции. Вы должны относиться ко всем моим размышлениям о гипотетических характеристиках необъявленных продуктов как к предположениям «только для развлечения», а не как к обещаниям или объявлениям.

person Eric Lippert    schedule 08.10.2009
comment
Еще одна связанная с этим функция, которую я хотел бы увидеть, - это средство, с помощью которого инициализаторы полей могут использовать параметры конструктора. Насколько я понимаю, инициализаторы полей фактически представляют собой просто код, вставленный перед первым оператором конструктора, и запускаются в этом контексте, поэтому они могут иметь доступ к этим параметрам, если язык предоставляет средства для этого. Предлагаемая мной реализация: синтаксис, подобный полям, чтобы указать, что определенный именованный параметр коонструктора данного типа будет доступен для инициализаторов полей; все конструкторы этого типа должны иметь такой параметр ... - person supercat; 20.12.2012
comment
... или присоединиться к тому, что делает. Это позволило бы чему-то вроде класса, представляющего коллекцию указанного конструктором (и неизменяемого) размера, иметь объявление массива, инициализирующее его с правильным размером. Если это единственный раз, когда эта ссылка будет когда-либо написана, включение ее в объявление кажется более приятным, чем необходимость ее объявления в одном месте и инициализации в другом. - person supercat; 20.12.2012
comment
@supercat: Интересная идея. И действительно, группа разработчиков C # рассматривает несколько иной механизм. Они рассматривают возможность добавления синтаксических сахаров в конструкторы, чтобы упростить выражение идеи, что этот формальный параметр ctor инициализирует это поле только для чтения, чтобы упростить краткое написание неизменяемых типов. Однако я не ожидал, что эта функция появится в ближайшее время. - person Eric Lippert; 20.12.2012
comment
Рад, что вам понравилась идея; Я надеюсь, что команды C # и vb.net смогут включать версии, в которых переданная вещь становится реальным полем (с заданной доступностью), автоматическим свойством (аналогично) или переменной, которую можно использовать только в инициализаторах или конструкторе. В vb.net можно достичь желаемой семантики, если интересующие значения параметров должны храниться в полях, и если добавлен дополнительный уровень наследования (если конструктор базового класса хранит значения в полях, инициализаторы производного класса можно их использовать), но это немного некрасиво. Я не думаю, что C # вообще может это сделать. - person supercat; 21.12.2012

Нет, к сожалению нет. Мне бы очень понравилась функция, которая могла бы выглядеть так:

public readonly string Name { get; }

или (немного странно)

public readonly string Name { get; readonly set; }

Это будет преобразовано во что-то вроде:

private readonly string <>_Name;

public string Name { get { return <>_Name; } }

Хитрость в том, что вызовы установщика будут разрешены, но только внутри конструктора. Такие вызовы будут преобразованы непосредственно в назначения для резервного поля.

Мне бы очень, очень понравилась такая функция. Может быть, для C # 5 ...

person Jon Skeet    schedule 08.10.2009
comment
Я предпочитаю ваш первый пример, но не следует ли также указывать ключевое слово set, даже если свойство всегда имеет сеттер? Тем более, что сеттер может иметь разные уровни доступа, даже если он readonly (верно? Я думаю о private и protected.) - person Blixt; 08.10.2009
comment
... даже если свойство всегда ... - чтобы уточнить, я имею в виду автоматические свойства, а не обычные свойства. - person Blixt; 08.10.2009
comment
@Blixt: Возможно. Я предполагаю, что подразумевается, что это автоматическое свойство, поэтому должен быть какой-то способ его установить ... Я подозреваю, что любая комбинация где-то будет неудобной :) - person Jon Skeet; 08.10.2009
comment
Я предполагаю. Но что, если вы измените private в третьем блоке кода на protected? Каким должен быть сокращенный код для такого вывода? - person Blixt; 08.10.2009
comment
@Blixt: У тебя не должно быть такой возможности, ИМО. Автоматические свойства всегда имеют частные резервные поля ... и я бы не хотел, чтобы в любом случае можно было устанавливать только для чтения из производных конструкторов. - person Jon Skeet; 08.10.2009
comment
Верно, но я бы сказал, что это потому, что нет никаких причин, по которым поле поддержки доступно. Для readonly ситуация иная, поскольку к вспомогательному полю должен напрямую обращаться ваш код (после компиляции). И поскольку возможно иметь поле protected, вы можете предотвращать какой-то случай, когда protected readonly имеет смысл, только поддерживая private. Я бы тоже не стал использовать protected, но я видел случаи, когда ограничение функциональности на основе таких предположений препятствовало некоторым изящным функциям (например, where T : Enum.) - person Blixt; 08.10.2009
comment
Что ж, вы можете сделать получатель доступным для производных классов - и если вы уже думаете, что производный класс может захотеть иметь возможность устанавливать значение поля, что мешает вам создать защищенный конструктор, который принимает значение для установки? Думаю, я в любом случае не слишком сильно чувствую это, но главное, чтобы эта функция была в первую очередь в языке :) - person Jon Skeet; 08.10.2009
comment
Я понимаю вашу точку зрения, и я тоже не так уж чувствителен к ней =) Но моя точка зрения заключается в том, что следует избегать запрета функциональности, которая практически присутствует, если у вас нет очень веской причины для этого. - person Blixt; 08.10.2009
comment
Я видел, как люди где-то еще просили о поддержке методов, которые можно вызывать только из конструктора, но которые могут изменять переменные только для чтения. Возможно, сеттер мог бы быть такой функцией. Я не уверен, как бы вы назвали их в C # - управляемое ключевое слово initonly в C ++ на самом деле более информативно, чем ключевое слово C # readonly. - person Simon; 09.10.2009
comment
@Simon: Я раньше не слышал об этом запросе функции, но он имеет большой смысл. - person Jon Skeet; 09.10.2009

readonly может применяться только к полям, поэтому я не верю.

Не могли бы вы просто использовать:

public readonly MyType MyProperty;

поскольку в любом случае он может быть назначен только из конструктора?

person JDunkerley    schedule 08.10.2009
comment
Хорошие гуру дизайна убьют вас за это, но я даю вам +1, потому что это действительно работает и никогда не вызывает никаких проблем на практике, а также в качестве компенсации за будущие отрицательные голоса. - person erikkallen; 08.10.2009
comment
См. Мой ответ Яну Баннистеру ... Есть множество причин не использовать общедоступные поля, даже те, которые предназначены только для чтения. - person Jon Skeet; 08.10.2009

Нет, ты никак не сможешь это сделать. Фактически, я не понимаю, зачем вам получить значение свойства, которое не было установлено ранее. По очевидным причинам вы не можете установить значение, если нет ни set средства доступа, ни поля поддержки.

person Anton Gogolev    schedule 08.10.2009
comment
У вас должна быть возможность установить его - но только из конструктора, как и в любом обычном поле только для чтения. - person Jon Skeet; 08.10.2009

Это действительно запутанный приятель.

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

person Jan Bannister    schedule 08.10.2009
comment
В этот момент вы теряете все преимущества свойств, включая исходную и двоичную совместимость, когда в конечном итоге хотите написать более полноценную реализацию свойства. Поля публичных экземпляров - плохая идея, ИМО. - person Jon Skeet; 08.10.2009
comment
Обычно я согласен с тем, что вам никогда не следует использовать общедоступные поля. Но это странный вариант использования. Он только для чтения, он не предназначен для записи. - person Jan Bannister; 08.10.2009
comment
@Jan: представьте, если вы скомпилируете свое поле readonly, а затем оно будет заменено свойством только с общедоступным аксессором get (которое все еще может возвращать значение поля private readonly). Это нарушит двоичную совместимость. - person Blixt; 08.10.2009
comment
@Jan: То, что он доступен только для чтения, не означает, что вы, возможно, не захотите в конечном итоге добавить туда дополнительную логику. Точно так же философское возражение против раскрытия полей (они являются деталями реализации, в отличие от свойств, которые являются частью API) не исчезает только потому, что они доступны только для чтения. Но рада, что книга вам понравилась :) - person Jon Skeet; 08.10.2009
comment
Вы упустили еще одно преимущество свойств перед полями: свойства могут быть членами интерфейсов, а поля - нет. - person finnw; 03.11.2009
comment
@Blixt, @ Тони Пони ОК ОК ОК. Все это прекрасные комментарии, но все они касаются возможных будущих изменений, а не самого вопроса. Итак, вы слишком долго разрабатываете свои ответы. Это обычное дело, не беспокойтесь об этом. - person Jan Bannister; 04.11.2009