Почему String.Empty не является константой?

В .NET почему String.Empty только для чтения вместо константы? Мне просто интересно, знает ли кто-нибудь, по какой причине было принято это решение.


person travis    schedule 03.02.2009    source источник
comment
Этот вопрос может решить эту проблему, краткий ответ: никто не знает ...   -  person gdoron is supporting Monica    schedule 15.12.2011
comment
Да, +1 за ответ Эрика Липперта, спасибо!   -  person travis    schedule 15.12.2011
comment
В частности, учитывая, что Decimal.Zero является константой (с точки зрения пользователя, то есть ...)   -  person Hamish Grubijan    schedule 13.03.2012


Ответы (4)


Причина, по которой static readonly используется вместо const, связана с использованием с неуправляемым кодом, как указано Microsoft здесь в Версия 2.0 инфраструктуры общего языка с общим исходным кодом. Файл для просмотра - sscli20\clr\src\bcl\system\string.cs.

Константа Empty содержит значение пустой строки. Нам нужно вызвать конструктор String, чтобы компилятор не пометил это как литерал.

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

Я нашел эту информацию в этой удобной статье на CodeProject.

person Jeff Yates    schedule 03.02.2009
comment
Я был бы очень признателен, если бы вы могли объяснить этот комментарий (потому что Джон Скит не мог ...) см. Здесь: stackoverflow.com/questions/8462697/ - person gdoron is supporting Monica; 12.12.2011
comment
@gdoron: Мое предположение (и это предположение) таково. Когда значение определяется как литерал (константа), его значение вставляется в те места, где на него ссылаются, тогда как, когда оно не определено как литерал, делается ссылка на источник значения, а фактическое значение извлекается во время выполнения. Я подозреваю, что последний может гарантировать, что правильная сортировка строки происходит между нативным и .NET во время выполнения - если бы это был литерал, возможно, нативный компилятор должен был бы каким-то образом вытащить буквальное значение в свой собственный код, что, вероятно, не достижимый. Однако это все лишь предположения с моей стороны. - person Jeff Yates; 12.12.2011
comment
Это означает, что для значений параметров по умолчанию в методах нужно использовать, а не string.Empty. Что немного раздражает. - person nicodemus13; 18.10.2012
comment
может выглядеть ошибкой, а string.Empty указывает на преднамеренное намерение - person Christopher Stevenson; 17.05.2013
comment
@JeffYates Я бы добавил, что тот факт, что это непоследовательно, уже раздражает. Люди увидят остальную часть кода и зададутся вопросом, почему он здесь использует вместо String.Empty ?. Я серьезно подумываю о том, чтобы больше не использовать String.Empty только по этой причине. - person julealgon; 04.08.2014

Я думаю, здесь много путаницы и плохих отзывов.

Прежде всего, const поля являются static членами (не членами экземпляра).

См. Раздел 10.4 Константы спецификации языка C #.

Несмотря на то, что константы считаются статическими членами, объявление константы не требует и не допускает модификатора static.

Если public const члены статичны, нельзя считать, что константа создаст новый объект.

Учитывая это, следующие строки кода делают в точности то же самое в отношении создания нового объекта.

public static readonly string Empty = "";
public const string Empty = "";

Вот примечание от Microsoft, объясняющее разницу между двумя:

Ключевое слово readonly отличается от ключевого слова const. Поле const может быть инициализировано только при объявлении поля. Поле только для чтения может быть инициализировано либо в объявлении, либо в конструкторе. Следовательно, поля только для чтения могут иметь разные значения в зависимости от используемого конструктора. Кроме того, в то время как поле const является константой времени компиляции, поле readonly может использоваться для констант времени выполнения, ...

Итак, я считаю, что единственный правдоподобный ответ здесь - это Джефф Йейтс.

person bruno conde    schedule 03.02.2009
comment
+1 за добрые слова и пояснения по поводу спецификации C # для const и static только для чтения. - person Jeff Yates; 03.02.2009
comment
Перечитывая это, я не согласен с тем, что const string и static readonly string делают то же самое. В связанном коде подставляются значения Const, тогда как ссылки на статические значения только для чтения. Если у вас есть const в библиотеке A, которая используется библиотекой B, библиотека B заменит все ссылки на эту const переменную ее буквальным значением; если бы эта переменная была static readonly, на нее была бы сделана ссылка, и ее значение было бы определено во время выполнения. - person Jeff Yates; 16.08.2012
comment
Точка зрения Джеффа важна при обращении к библиотекам. Если вы перекомпилируете A и распространите его, без перекомпиляции B, B по-прежнему будет использовать старые значения. - person Mark Sowul; 04.02.2013

String.Empty read only instead of a constant?

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

Если вы оставите свою строку для чтения только в одном месте, так как это String.Empty, программа сохранит ту же строку только в одном месте и прочитает ее или обратится к ней - сохраняя данные в памяти как минимум.

Кроме того, если вы скомпилируете любую dll, используя String.Empty как const и по какой-либо причине изменив String.Empty, то скомпилированная dll больше не будет работать так же, потому что cost заставляет внутренний код фактически сохранять копию строка при каждом вызове.

См. Этот код, например:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

будет получен компилятором как:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

и вызов сборки

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Изменить: исправленная опечатка

person Aristos    schedule 18.05.2013
comment
Итак, это означает, что константная строка всегда должна быть создана с классом, содержащим эту константу? Похоже, что тогда гораздо лучше использовать static readonly. - person the berserker; 27.06.2016
comment
@theberserker - это лучше, но у вас есть все возможности для использования. - person Aristos; 28.06.2016
comment
›Тогда скомпилированная dll больше не будет работать так же, как стоимость, заставляющая внутренний код фактически сохранять копию строки при каждом вызове. @ Аристос. Это не совсем так. После компиляции кода на копию строки будет ссылаться в блоке TEXT исполняемого файла, и весь код будет просто ссылаться на тот же самый блок памяти. То, что вы процитировали на втором этапе, - это просто промежуточный шаг. - person Peter Dolkens; 04.08.2016
comment
@ user1533523 спасибо за замечание - я сделаю тест, когда найду время, чтобы проверить это - person Aristos; 04.08.2016
comment
Как вы получили этот ассемблерный код? C # не компилируется в сборку! - person jv110; 24.02.2018
comment
@ jv110 Остановитесь (точка останова) с там отладчиком (если я хорошо помню) и попросите показать мне код сборки. - person Aristos; 24.02.2018

Этот ответ существует для исторических целей.

Первоначально:

Потому что String - это класс и поэтому не может быть константой.

Расширенное обсуждение:

При проверке этого ответа было создано много полезных диалогов, и вместо его удаления этот контент воспроизводится напрямую:

В .NET (в отличие от Java) строка и строка абсолютно одинаковы. И да, вы можете иметь константы строковых литералов в .NET - DrJokepu 03 фев.

Вы хотите сказать, что у класса не может быть констант? - StingyJack 3 фев.

Да, объекты должны использоваться только для чтения. Только структуры могут создавать константы. Я думаю, что когда вы используете string вместо String, компилятор меняет const на readonly для вас. Все для того, чтобы сделать программистов на C счастливыми. - Гарри Шатлер, 03 фев. 2009, 16:59

tvanfosson просто объяснил это более подробно. «X не может быть константой, потому что содержащий Y класс» было слишком контекстно-зависимым;) - Леонидас 3 фев. 2009 в 17:01

string.Empty - это статическое свойство, которое возвращает экземпляр класса String, а именно пустую строку, а не сам класс строки. - tvanfosson 3 фев.

Empty - это экземпляр класса String, доступный только для чтения (это не свойство). - senfo 03 фев.

Голова болит. Я все еще думаю, что прав, но теперь я менее уверен. Сегодня вечером требуется исследование! - Гарри Шатлер, 3 февраля 2009 г., 17:07

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

Гарри, тебе не нужно проводить никаких исследований. Думаю об этом. Строка - это класс. Empty - это экземпляр String. - senfo 03 фев. 2009 в 17:12

Есть кое-что, чего я не совсем понимаю: как вообще статический конструктор класса String может создать экземпляр класса String? Разве это не сценарий «курица или яйцо»? - DrJokepu 3 фев.

Этот ответ будет правильным почти для любого другого класса, кроме System.String. .NET делает много работы с особенным регистром для строк, и одна из них заключается в том, что вы МОЖЕТЕ иметь строковые константы, просто попробуйте. В этом случае Джефф Йейтс знает правильный ответ. - Джоэл Мюллер 3 фев.

Как описано в §7.18, константное выражение - это выражение, которое может быть полностью вычислено во время компиляции. Поскольку единственный способ создать ненулевое значение ссылочного типа, отличного от строки, - это применить новый оператор, и поскольку новый оператор не разрешен в константном выражении, единственное возможное значение для констант ссылочных типов кроме строки является нулем. Предыдущие два комментария были взяты непосредственно из спецификации языка C # и повторяют то, что упомянул Джоэл Мюллер. - senfo 4 фев.

person Garry Shutler    schedule 03.02.2009
comment
Пожалуйста, проголосуйте за правильный ответ. Если вы перейдете к определению, вы обнаружите, что оно находится в классе String и является экземпляром String. Тот факт, что он отображается в нижнем регистре, - это волшебство компилятора. - person Garry Shutler; 03.02.2009
comment
Это не я отрицал вас, но в .NET (в отличие от Java) string и String абсолютно одинаковы. И да, вы можете иметь константы строковых литералов в .NET. - person Tamas Czinege; 03.02.2009
comment
Я не делал тебе DV, но ты можешь меня немного подшутить. Вы хотите сказать, что у класса не может быть констант? - person StingyJack; 03.02.2009
comment
Да, объекты должны использоваться только для чтения. Только структуры могут создавать константы. Я думаю, что когда вы используете строку вместо String, компилятор меняет const на readonly для вас. Все для того, чтобы сделать программистов на C счастливыми. - person Garry Shutler; 03.02.2009
comment
tvanfosson просто объяснил это более подробно. X не может быть константой, потому что содержащий Y класс был слишком контекстно-зависимым;) - person Leonidas; 03.02.2009
comment
string.Empty - это статическое свойство, которое возвращает экземпляр класса String, а именно пустую строку, а не сам класс строки. - person tvanfosson; 03.02.2009
comment
Empty - это экземпляр, доступный только для чтения (это не свойство) класса String. - person senfo; 03.02.2009
comment
Голова болит. Я все еще думаю, что прав, но теперь я менее уверен. Сегодня вечером требуется исследование! - person Garry Shutler; 03.02.2009
comment
Пустая строка - это экземпляр класса строки. Empty - это статическое поле (не свойство, я исправлюсь) в классе String. В основном разница между указателем и тем, на что он указывает. Если бы это было не только для чтения, мы могли бы изменить, к какому экземпляру относится пустое поле. - person tvanfosson; 03.02.2009
comment
Гарри, тебе не нужно проводить никаких исследований. Думаю об этом. Строка - это класс. Empty - это экземпляр String. - person senfo; 03.02.2009
comment
Есть кое-что, чего я не совсем понимаю: как вообще статический конструктор класса String может создать экземпляр класса String? Разве это не сценарий курицы или яйца? - person Tamas Czinege; 03.02.2009
comment
Этот ответ будет правильным почти для любого другого класса, кроме System.String. .NET делает много работы с особенным регистром для строк, и одна из них заключается в том, что вы МОЖЕТЕ иметь строковые константы, просто попробуйте. В этом случае Джефф Йейтс знает правильный ответ. - person Joel Mueller; 03.02.2009
comment
Как описано в §7.18, константное выражение - это выражение, которое может быть полностью вычислено во время компиляции. - person senfo; 04.02.2009
comment
(продолжение) Поскольку единственный способ создать ненулевое значение ссылочного типа, отличного от строки, - это применить новый оператор, а поскольку новый оператор не разрешен в константном выражении, единственное возможное значение для констант ссылочные типы, отличные от строки, имеют значение NULL. - person senfo; 04.02.2009
comment
Предыдущие два комментария были взяты непосредственно из спецификации языка C # и повторяют то, что упомянул Джоэл Мюллер. - person senfo; 04.02.2009
comment
Я почти удалил этот ответ, так как появился гораздо лучший, но обсуждение в этих комментариях стоит продолжить. - person Garry Shutler; 04.02.2009
comment
@Garry, тебе повезло, я прочитал твой последний комментарий, иначе я бы тоже проголосовал против. Строка имеет специальную функцию в .NET: даже если это класс ref, она может быть константой. - person Shimmy Weitzhandler; 15.02.2011