Как реализовать свойство только для чтения
Мне нужно реализовать свойство только для чтения в моем типе. Кроме того, значение этого свойства будет установлено в конструкторе, и оно не будет изменено (я пишу класс, который предоставляет пользовательские маршрутизированные команды интерфейса для WPF, но это не имеет значения).
Я вижу два способа сделать это:
Со всеми этими ошибками FxCop, говорящими, что у меня нет публичных переменных-членов, кажется, что второй - правильный способ сделать это. Правильно?
Есть ли разница между свойством get only и членом только для чтения?
Буду признателен за любые комментарии/советы и т.д.
Ответы
Ответ 1
Versioning:
Я думаю, что это не имеет большого значения, если вас интересует только совместимость источников.
Использование свойства лучше для двоичной совместимости, так как вы можете заменить его свойством, у которого есть сеттер, не нарушая скомпилированный код в зависимости от вашей библиотеки.
Конвенция:
Вы следуете конвенции. В таких случаях, когда различия между двумя возможностями относительно незначительны в соответствии с соглашением, лучше. Один случай, когда он может вернуться, чтобы укусить вас, - это код, основанный на отражении. Он может принимать только свойства, а не поля, например редактор свойств/просмотрщик.
Сериализация
Переход от поля к собственности, вероятно, приведет к разрыву множества сериализаторов. И AFAIK XmlSerializer
выполняет сериализацию публичных свойств, а не публичных полей.
Использование Autoproperty
Еще одна общая вариация - это использование автопроцессора с помощью частного сеттера. Хотя это и коротко, и свойство не обеспечивает постоянство чтения. Поэтому я предпочитаю другие.
Поле Readonly является самодокументированным
Есть одно преимущество поля:
Это дает понять с первого взгляда на публичный интерфейс, что он фактически непреложный (запрет на отражение). Если в случае свойства вы можете видеть только, что вы не можете его изменить, вам придется обратиться к документации или реализации.
Но, честно говоря, я использую первый из них довольно часто в коде приложения, так как я ленив. В библиотеках я, как правило, более тщательно и придерживаюсь соглашения.
С# 6.0 добавляет автоматические свойства readonly
public object MyProperty { get; }
Поэтому, когда вам не нужно поддерживать старые компиляторы, вы можете иметь действительно свойство readonly с кодом, который так же кратким, как поле readonly.
Ответ 2
Второй способ - предпочтительный вариант.
private readonly int MyVal = 5;
public int MyProp { get { return MyVal;} }
Это гарантирует, что MyVal
может быть назначено только при инициализации (его также можно установить в конструкторе).
Как вы уже отметили - таким образом вы не подвергаете внутреннему члену, что позволяет вам изменить внутреннюю реализацию в будущем.
Ответ 3
С введением С# 6 (в VS 2015) теперь вы можете иметь get
- только автоматические свойства, в которых неявное поле поддержки readonly
(т.е. значения могут быть назначены в конструкторе, но не в другом месте)
public string Name { get; }
public Customer(string name) // Constructor
{
Name = name;
}
private void SomeFunction()
{
Name = "Something Else"; // Compile-time error
}
Теперь вы можете также инициализировать свойства (с или без сеттера) inline:
public string Name { get; } = "Boris";
Возвращаясь к вопросу, это дает вам преимущества варианта 2 (открытый член - это свойство, а не поле) с кратностью варианта 1.
К сожалению, он не гарантирует гарантии неизменности на уровне открытого интерфейса (как в @CodesInChaos указывает на самодокументацию), потому что для потребителя класса, не имеющего сеттера, неотличим от наличия частного сеттер.
Ответ 4
Вы можете сделать это:
public int Property { get { ... } private set { ... } }
Ответ 5
Я согласен, что второй вариант предпочтительнее. Единственной реальной причиной этого предпочтения является общее предпочтение, что классы .NET не имеют открытых полей. Однако, если это поле доступно только для чтения, я не вижу, как будут существовать какие-либо реальные возражения, кроме отсутствия согласованности с другими свойствами. Реальное различие между полем readonly и get-only заключается в том, что поле readonly гарантирует, что его значение не изменится в течение всего срока службы объекта, а свойство get-only не будет.
Ответ 6
Второй способ является предпочтительным из-за инкапсуляции. Конечно, поле readonly может быть общедоступным, но это противоречит идиомам С#, в которых вы имеете доступ к данным через свойства, а не поля.
Обоснование этого заключается в том, что свойство определяет открытый интерфейс, и если реализация поддержки этого свойства изменяется, вы не нарушаете остальную часть кода, потому что реализация скрыта за интерфейсом.
Ответ 7
еще один способ (мой любимый), начиная с С# 6
private readonly int MyVal = 5;
public int MyProp => MyVal;
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#expression-body-definitions