Ответ 1
Важная часть - это не то, что происходит в этом классе, но что происходит, когда другой класс использует (и ссылки) на него. Позвольте мне объяснить еще один пример:
Предположим, у вас есть Assembly1.dll, содержащий класс, объявляющий
public static const int SOME_ERROR_CODE=0x10;
public static readonly int SOME_OTHER_ERROR_CODE=0x20;
и другой класс, потребляющий это, например,
public int TryFoo() {
try {foo();}
catch (InvalidParameterException) {return SOME_ERROR_CODE;}
catch (Exception) { return SOME_OTHER_ERROR_CODE;}
return 0x00;
}
Вы компилируете свой класс в Assembly2.dll и связываете его с Assembly1.dll, как и ожидалось, ваш метод вернет 0x10 по недопустимым параметрам, 0x20 для других ошибок, 0x00 при успехе.
В частности, если вы создадите Assembly3.exe, содержащий что-то вроде
int errorcode=TryFoo();
if (errorcode==SOME_ERROR_CODE) bar();
else if (errorcode==SOME_OTHER_ERROR_CODE) baz();
Он будет работать как ожидается (после соединения с Assembly1.dll и Assembly2.dll)
Теперь, если вы получаете новую версию Assembly1.dll, которая имеет
public const int SOME_ERROR_CODE=0x11;
public readonly int SOME_OTHER_ERROR_CODE=0x21;
Если вы перекомпилируете Assembly3.exe и связали последний фрагмент с новым Assembly1.dll и неизменным Assembly2.dll, он перестанет работать как ожидалось:
bar() НЕ будет вызываться правильно: Assembly2.dll помнит LITERAL 0x20, который не является тем же литералом 0x21, что Assembly3.exe читает из Assembly1.dll
baz() будет вызываться правильно: Both Assembly2.dll и Assembly3.exe ссылаются на ссылку SYMBOL REFERENCE, называемую SOME_OTHER_ERROR_CODE, которая в обоих случаях разрешена текущей версией Assembly1.dll, поэтому в обоих случаях это 0x21.
Вкратце: a const
создает a LITERAL
, a readonly
создает a SYMBOL REFERENCE
.
LITERALS
являются внутренними для фреймворка и не могут быть распределены и, таким образом, использованы собственным кодом.
So
public static readonly String Empty = "";
создает SYMBOL REFERENCE
(сбрасывается во время первого использования вызовом Stnt cosntuctor), который может быть распределен таким образом из native, а
public static const String Empty = "";
создал бы литерал, который не может.