Подтвердить что ты не робот

Как реализовать свойство только для чтения

Мне нужно реализовать свойство только для чтения в моем типе. Кроме того, значение этого свойства будет установлено в конструкторе, и оно не будет изменено (я пишу класс, который предоставляет пользовательские маршрутизированные команды интерфейса для WPF, но это не имеет значения).

Я вижу два способа сделать это:

  • class MyClass
    {
        public readonly object MyProperty = new object();
    }
    
  • class MyClass
    {
        private readonly object my_property = new object();
        public object MyProperty { get { return my_property; } }
    }
    

Со всеми этими ошибками FxCop, говорящими, что у меня нет публичных переменных-членов, кажется, что второй - правильный способ сделать это. Правильно?

Есть ли разница между свойством get only и членом только для чтения?

Буду признателен за любые комментарии/советы и т.д.

4b9b3361

Ответ 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 может быть общедоступным, но это противоречит идиомам С#, в которых вы имеете доступ к данным через свойства, а не поля.

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