Важной частью является не то, что происходит в этом классе, а то, что происходит, когда другой класс использует (и ссылается на него).Позвольте мне объяснить на другом примере:
Предположим, у вас есть 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 ссылаются на ССЫЛКУ СИМВОЛА, называемую SOME_OTHER_ERROR_CODE, которая в обоих случаях разрешена текущей версией Assembly1.dll, поэтому в обоих случаях она равна 0x21.
Короче: a const
создает LITERAL
, readonly
создает SYMBOL REFERENCE
.
LITERALS
являются внутренними для фреймворка и не могут быть упорядочены и, таким образом, использованы собственным кодом.
Таким образом,
public static readonly String Empty = "";
создает symbol reference
(восстанавливается во время первого использования при вызове куленту String), который можно маршалировать и использовать таким образом из native, в то время как
public static const String Empty = "";
создаст литерал, который не может.