Не объявлять изменяемые ссылочные типы только для чтения - почему бы и нет?

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

Предположительно, есть ситуации, когда я не хочу, чтобы экземпляр мог быть изменен, но не возражаю, если состояние экземпляра изменится (может быть синглтон. / Me готовится к пламени) Каковы последствия маркировки экземпляра только для чтения, если я хочу это?


person Sam Holder    schedule 03.03.2010    source источник


Ответы (4)


Нет никаких последствий (на основе времени выполнения / среды). Компилятор не испугается, ваша среда выполнения не взорвется, и в целом все будет хорошо.

Об этом предупреждает только FxCop (инструмент статического анализа, которым пользуются некоторые). Причины предупреждения объясняются в потоке, с которым вы связались (семантически может быть неясно, что объект на самом деле не «только для чтения», а только то, что переменная не может быть «переназначена»).

Лично я не согласен с правилом, поэтому я бы просто отключил его (если вы используете FxCop и это вас беспокоит).

person Noon Silk    schedule 03.03.2010
comment
спасибо, это то, что я хотел знать, я просто хотел быть уверен, что среда выполнения не будет делать никаких предположений об этом члене, основываясь на том факте, что он был помечен как только для чтения - person Sam Holder; 03.03.2010
comment
Читая статью, на которую ссылается Эрик, я не чувствую, что должен игнорировать это правило. Объявление ReadOnly может заставить реализовать поведение, совершенно отличное от ожидаемого. - person Rafa; 14.03.2014
comment
@Rafa: если поле, которое идентифицирует изменяемый объект класса, помечено как readonly, то копия ссылки предоставит живое представление состояния, инкапсулированного этим полем. Если поле не помечено readonly, то копия ссылки может быть отделена от состояния, инкапсулированного полем. То, что некоторые люди не знают, что readonly означает, когда применяется к ссылке на изменяемый объект, не означает, что его фактическое значение бесполезно. - person supercat; 18.03.2015

Интересный связанный с этим момент: изменяемые структуры только для чтения - плохая идея из-за ситуаций, подобных этой:

http://ericlippert.com/2008/05/14/mutating-readonly-structs/

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

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

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

person Eric Lippert    schedule 03.03.2010

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

Я бы отнесся к этому как к предложению больше, чем к правилу - конечно, есть случаи, когда это могло бы быть разумным, но должно использоваться с осторожностью. (В частности, я бы нервничал, если бы изменяемое состояние было выставлено внешнему миру.)

person Jon Skeet    schedule 03.03.2010

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

  • постоянная ссылка на изменяемый объект.
  • изменяемая ссылка на постоянный объект.

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

Неосмотрительные читатели, вероятно, тоже неосторожные писатели - ничего не могут с ними поделать, кроме:

const SourceRepository cvs = new ReadOnlyRepository(...);

В C ++ есть средства обеспечения постоянного указателя на постоянный объект (ссылки в C ++ немного отличаются):

Object const* const constantPointerToConstantObject = ...;

Это одна из немногих возможностей C ++, которые мне не хватает в C # / Java.

В D есть еще лучшее ключевое слово (неизменяемый), обеспечивающее транзитивную неизменяемость. Неизменяемость D позволяет компилятору производить оптимизацию, о которой вы беспокоитесь, и гарантирует безопасность. D также имеет const для непереходной константности, что означает, что как транзитивные, так и нетранзитивные формы полезны независимо друг от друга.

person richj    schedule 31.08.2010