Почему Microsoft советует не читать только поля с изменяемыми значениями?

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

int func(int arr[], ...){
    .
    .
    .
}

int func(int arr[SIZE], ...){
    .
    .
    .
}

int func(int* arr, ...){
    .
    .
    .
}

Итак, вы изменяете исходные значения.

Спасибо !!!

38
задан Weeble 10 May 2010 в 17:18
поделиться

6 ответов

Я полностью с вами согласен, и я действительно иногда использую readonly в своем коде для мутабельных ссылочных типов.

В качестве примера: У меня может быть некий private или protected член - скажем, List - который я использую в методах класса во всей его мутабельной красе (вызывая Add, Remove и т.д.). Возможно, я просто хочу установить защиту, чтобы гарантировать, что, несмотря ни на что, я всегда имею дело с одним и тем же объектом. Это защитит и меня, и других разработчиков от глупостей: а именно, от присвоения члена новому объекту.

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

Другими словами, если бы у меня было так:

protected List<T> InternalList { get; private set; }

Тогда я все еще мог бы установить InternalList = new List(); в любой произвольной точке кода в моем базовом классе. (Это потребовало бы очень глупой ошибки с моей стороны, да; но это было бы возможно.)

С другой стороны, это:

protected readonly List<T> _internalList;

делает безошибочно ясным, что _internalList может когда-либо ссылаться только на один конкретный объект (тот, которому _internalList установлен в конструкторе).

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

21
ответ дан 27 November 2019 в 03:43
поделиться

НЕ назначать экземпляры изменяемых типов полям только для чтения .

Я бегло просмотрел книгу Framework Design Guidelines (страницы 161–162), и в ней в основном говорится о том, что вы уже заметили. Есть дополнительный комментарий Джо Даффи, который объясняет смысл существования руководства:

Это руководство пытается защитить вас от веры в то, что вы раскрыли глубоко неизменяемый граф объектов, хотя на самом деле он неглубокий, а затем пишете код, предполагающий неизменность всего графа.
- Джо Даффи

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

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

Чтобы исправить эту неприятную ситуацию, было составлено руководство. Хотя я думаю, что его совет является разумным с точки зрения человека (не всегда очевидно, какие типы являются изменяемыми, а какие нет, если не искать их определения, и это слово предполагает глубокую неизменяемость), я иногда желаю, чтобы, когда дело доходит до объявления константности, C # предлагал свободу, аналогичную той, которую предлагает C ++, где вы можете определить const либо для указателя, либо для объекта, на который указывает, либо на обоих или ничего.

7
ответ дан 27 November 2019 в 03:43
поделиться

В конце концов, это всего лишь рекомендации. Я точно знаю, что люди в Microsoft часто не следуют всем рекомендациям.

1
ответ дан 27 November 2019 в 03:43
поделиться

У Microsoft есть несколько таких необычных советов. Другой момент, который сразу приходит в голову, - это не вкладывать универсальные типы в открытые члены, такие как List > . Я стараюсь избегать этих конструкций там, где это возможно, но игнорирую советы для новичков, когда считаю, что их использование оправдано.

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

2
ответ дан 27 November 2019 в 03:43
поделиться

Синтаксис, который вы ищете, поддерживается языком C ++ / CLI:

const Example^ const obj;

Первая константа делает объект, на который указывает ссылка, неизменяемым, вторая - неизменяемой ссылкой. Последнее эквивалентно ключевому слову readonly в C #. Попытки обойти его приводят к ошибке компиляции:

Test^ t = gcnew Test();
t->obj = gcnew Example();   // Error C3892
t->obj->field = 42;         // Error C3892
Example^ another = t->obj;  // Error C2440
another->field = 42; 

Однако это дым и зеркала. Неизменяемость проверяется компилятором, а не средой CLR. Другой управляемый язык может изменить и то, и другое. Это корень проблемы, CLR просто не поддерживает его.

2
ответ дан 27 November 2019 в 03:43
поделиться

Кажется естественным, что если поле доступно только для чтения, вы не сможете изменить значение или что-либо связанное с ним . Если бы я знал, что Bar - это поле Foo, доступное только для чтения, я бы, очевидно, не мог сказать

Foo foo = new Foo();
foo.Bar = new Baz();

Но я мог бы избежать наказания, сказав

foo.Bar.Name = "Blah";

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

25
ответ дан 27 November 2019 в 03:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: