Есть ли смысл отмечать приватное поле только для чтения? - PullRequest
1 голос
/ 12 июля 2011
public class Foo
{
    private readonly Bar _bar;
}

public class Foo2
{
    private Bar _bar;
}

Я не вижу никакой выгоды в том, чтобы пометить его как только для чтения.Это личное, и если я пытаюсь сделать что-то внутренне, чтобы изменить это, я становлюсь глупым, так как знаю, как хочу, чтобы мой класс вел себя?Итак, какой смысл?Я не думаю, что здесь есть какой-то прирост производительности, так что этого не может быть.

Ответы [ 6 ]

19 голосов
/ 12 июля 2011

Всегда приятно, когда компилятор мешает тебе быть глупым.

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

Он также сообщает другим читающим ваш код людям, что поле никогда не изменится

4 голосов
/ 12 июля 2011

Когда вы написали этот класс, вы знаете, как вы хотите, чтобы он вел себя.

Но:

  • Вы можете ошибиться, когда впервые пишете урок.
  • Возможно, вы не помните свои намерения, когда вернетесь позже, чтобы изменить класс.
  • Другой программист может не знать ваших намерений, когда они изменят класс позже.

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

2 голосов
/ 12 июля 2011

Вы правы, выигрыша в производительности нет. Однако здесь есть ключевые отличия:

Если вы намерены создать класс, в котором вы не пытаетесь изменить _bar, это действительно должно быть поле только для чтения. Здесь я вижу 2 вещи:

  1. Поля только для чтения могут быть инициализированы только встроенными или во время строительства (безопасность).
  2. Он защищает от других программистов, которые приходят и думают: «О, это не только для чтения. Я могу изменить его».

Теперь, НЕ должно быть доступно только для чтения, если вы планируете сохранять его нулевым, пока не будет вызван другой метод для его инициализации. Но для этого я бы посмотрел на Lazy<T>.


По сути, это ваш звонок. Если вы действительно собираетесь ТОЛЬКО ТОЛЬКО 1018 *, модифицирующий этот класс, я бы все же сказал, что следуйте этим правилам. Это лучший способ сделать это. :)

1 голос
/ 08 октября 2012

Предположим, что класс должен содержать изменяемый набор T и имеет закрытое поле T[] theArray. Существует несколько способов настройки класса:

  1. Это поле может быть изменяемой ссылкой на массив, который никогда не будет изменен; Чтобы внести изменения в список, нужно создать новый массив соответствующего размера, скопировать в него данные, изменить его соответствующим образом, а затем сохранить ссылку на новый массив в поле. Обратите внимание, что класс может недорого выставлять снимки содержимого массива только для чтения, помещая массив в `ReadOnlyCollection`; создание снимка не потребует копирования массива.
  2. Это поле может быть изменяемой ссылкой на изменяемый массив. Большинство обновлений будут выполняться путем изменения существующего массива, но обновления, выходящие за пределы конца массива, создадут новый с элементами, скопированными из старого. Вот как работает `List`. Обратите внимание, что обертывание массива в `ReadOnlyCollection` может привести к тому, что какое-то время будет вести себя как представление только для чтения живых данных некоторое время, но в какой-то момент в будущем может стать моментальным снимком данных.
  3. Это поле может быть неизменной ссылкой на изменяемый массив, если массив либо достаточно велик, чтобы содержать все, что когда-либо будет добавлено. Маловероятно для списка переменной длины, но в некоторых приложениях может быть целесообразно заранее указать и предварительно выделить место для максимального количества элементов. В этом сценарии оборачивание массива в коллекцию ReadOnlyCollection приведет к оперативному просмотру его состояния.

Три разных подхода имеют разные значения для таких вещей, как безопасность потоков. Первый можно сделать потокобезопасным, если последовательность readref-copy-modify-writeref помещена в цикл Interlocked.CompareExchange. Последнее может быть сделано поточно-безопасным, если сделать запись отдельных элементов поточно-ориентированной. Второй, однако, может быть сделан потокобезопасным только за счет того, что все операции записи имеют общую блокировку, которая является общей для списка в целом, и требуют, чтобы читатели дважды проверяли свои операции для обеспечения согласованности, или же требовали, чтобы все права на чтение и запись должны проходить через общую блокировку.

1 голос
/ 12 июля 2011

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

public MyClass(string user, string password){
  this.username = username;
  this.password = password;
  this.connect();
}

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

0 голосов
/ 12 июля 2011

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

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

В противном случае, использование соглашений для (повторного) осуществления намерения - неплохая идея.

...