Значение запутанного комментария над строкой. Пусто в источнике .NET / BCL?

Я пытаюсь понять, почему string.Empty это readonly, а не const. Я видел это сообщение, но мне не понятен комментарий Microsoft по этому поводу. Как Джон Скит написал в своем комментарии «Я не знаю - для меня это не имеет особого смысла. , если честно ... "

Версия 2.0 инфраструктуры общего языка с общим исходным кодом . string.cs находится в sscli20 \ clr \ src \ bcl \ system \ string.cs

// The Empty constant holds the empty string value.
//We need to call the String constructor so that the compiler doesn't mark this as a literal.
//Marking this as a literal would mean that it doesn't show up as a field which we can access 
//from native.
public static readonly String Empty = ""; 

Я не вижу здесь вызова конструктора String, и, кроме того, он помечен как буквальный - ""

Может кто-нибудь объяснить мне простым текстом, что означает комментарий и почему string.Empty readonly, а не const?


Обновление:
Эрик Липперт к настоящему времени прокомментировал удаленный ответ:

За обедом я спросил об этом одного из старожилов C #, и он не вспомнил, почему было принято это решение, но предположил, что оно как-то связано с интернированием.


person gdoron is supporting Monica    schedule 13.12.2011    source источник
comment
Может быть, это один из тех комментариев, которые когда-то имели смысл, но затем код был изменен, и он больше не имеет смысла ... не то, чтобы я когда-либо делал это или что-то в этом роде ... свистит, уходя < / я>   -  person    schedule 13.12.2011
comment
Почему это не константа - потому что тогда вы не сможете весело провести время, выполняя typeof(string).GetField("Empty").SetValue(null, null); или typeof(string).GetField("Empty").SetValue(null, " "); - mwahahah; мваааахахахахахаххх; MWWWWAAAAAHAHAHAHAHAHH!   -  person Marc Gravell    schedule 13.12.2011
comment
@MarcGravell, где Эрик Липперт, когда он нужен. Помогите мне супермен ...   -  person gdoron is supporting Monica    schedule 13.12.2011
comment
Если Джон Скит этого не понимает, то вы обречены   -  person Bojan Kogoj    schedule 13.12.2011
comment
Судя по комментарию, в какой-то момент в прошлом константы не считались полями.   -  person Raymond Chen    schedule 13.12.2011
comment
Что очень забавно (и грустно), что ответ, в котором содержался этот комментарий, был принят + 49 голосов, и никто, включая команду CLR, это не понимает.   -  person gdoron is supporting Monica    schedule 15.12.2011


Ответы (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 запоминает ЛИТЕРАЛЬНЫЙ 0x20, который не является тем же литералом 0x21, который Assembly3.exe считывает из Assembly1.dll.

baz () будет вызываться правильно: как Assembly2.dll, так и Assembly3.exe ссылаются на СИМВОЛ REFERENCE, называемый SOME_OTHER_ERROR_CODE, который в обоих случаях разрешается текущей версией Assembly1.dll, таким образом, в обоих случаях это 0x21.

Вкратце: const создает LITERAL, readonly создает SYMBOL REFERENCE.

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

So

public static readonly String Empty = ""; 

создает symbol reference (восстанавливается во время первого использования вызовом String cosntuctor), который может быть упорядочен и таким образом использован из нативного, в то время как

public static const String Empty = ""; 

создаст литерал, который не может.

person Eugen Rieck    schedule 18.12.2011
comment
Каковы преимущества того, что string.Empty не запоминается и не будет изменен. const может быть в порядке, не так ли? - person gdoron is supporting Monica; 19.12.2011
comment
Я подозреваю, что это связано с маршалингом: комментарий к коду говорит о возможности вызывать его из нативного кода, а литералы не маршалируются. - person Eugen Rieck; 19.12.2011
comment
Я хотел бы понять, почему литералы нельзя упорядочивать ... Чем отличается литерал от ссылки, возвращающей одно и то же значение? - person Camilo Martin; 29.01.2012
comment
Хотя этот ответ правильно описывает, почему используется readonly, он никоим образом не отвечает на вопрос. - person Mark Hurd; 08.01.2013
comment
@MarkHurd Последнее предложение OQ - почему string.Empty только для чтения, а не константа - так я подумал, что если он правильно описывает, почему используется только чтение, он действительно отвечает на вопрос. Хотя я могу ошибаться! - person Eugen Rieck; 08.01.2013
comment
@EugenRieck Хорошее замечание. Я видел заголовок и большую часть обсуждения и комментариев, но пропустил это :-( - person Mark Hurd; 08.01.2013
comment
@MarkHurd Итак, OQ состоит из двух частей: последнюю мы обсуждали выше. Первое: что означает комментарий. Комментарий: не делайте это буквальным, потому что мы не можем получить доступ к лиералу из родного. В последней части моего ответа (начиная с «Вкратце») говорится о том, что литералы немаршируемы и, следовательно, не могут использоваться вне фреймворка - ИМХО, это отвечает на первую часть OQ. - person Eugen Rieck; 08.01.2013