В чем разница между String.Empty и “” (пустая строка)?

StackOverflow https://stackoverflow.com/questions/151472

  •  02-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

В .NET до версии 2.0, "" создает объект, в то время как string.Empty не создает объектассылка, что делает string.Empty более эффективно.

В версии 2.0 и более поздних версиях .NET все вхождения "" ссылаются на тот же строковый литерал, что означает "" эквивалентно .Empty, но все же не так быстро , как .Length == 0.

.Length == 0 это самый быстрый вариант, но .Empty это делает код немного чище.

Смотрите на Спецификация .NET для получения дополнительной информации.

Другие советы

в чем разница между String.Empty и "", и являются ли они взаимозаменяемыми

string.Empty является полем, доступным только для чтения, тогда как "" является константой времени компиляции.Места , где они ведут себя по - другому , - это:

Значение параметра по умолчанию в C # 4.0 или выше

void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
    //... implementation
}

Выражение Case в операторе switch

string str = "";
switch(str)
{
    case string.Empty: // Error: A constant value is expected. 
        break;

    case "":
        break;

}

Аргументы атрибута

[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression 
//        or array creation expression of an attribute parameter type

Предыдущие ответы были правильными для .NET 1.1 (посмотрите на дату публикации, на которую они ссылались:2003).Начиная с .NET 2.0 и более поздних версий, разницы практически нет.JIT в конечном итоге все равно будет ссылаться на один и тот же объект в куче.

Согласно спецификации C #, раздел 2.4.4.5:http://msdn.microsoft.com/en-us/library/aa691090 (ПРОТИВ 71).aspx

Каждый строковый литерал не обязательно приводит к созданию нового экземпляра string.Когда два или более строковых литерала, эквивалентных в соответствии с оператором равенства строк (раздел 7.9.7), появляются в одной сборке, эти строковые литералы ссылаются на один и тот же экземпляр string.

Кто-то даже упоминает об этом в комментариях к посту Брэда Абрама

Подводя итог, практический результат "" vs.Строка.Пустое значение равно нулю.JIT разберется с этим в конце концов.

Лично я обнаружил, что JIT намного умнее меня, и поэтому я стараюсь не слишком умничать с подобными оптимизациями микрокомпилятора.JIT развернет циклы for (), удалит избыточный код, встроенные методы и т.д. Лучше и в более подходящее время, чем я или компилятор C # могли когда-либо ожидать заранее.Позвольте JIT выполнять свою работу :)

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

Другое отличие заключается в том, что String.Empty генерирует CIL-код большего размера.Хотя код для ссылки на "" и String.Empty имеет одинаковую длину, компилятор не оптимизирует конкатенацию строк (см. Статью Эрика Липперта запись в блоге) для строки.Пустые аргументы.Следующие эквивалентные функции

string foo()
{
    return "foo" + "";
}
string bar()
{
    return "bar" + string.Empty;
}

сгенерируйте этот IL

.method private hidebysig instance string foo() cil managed
{
    .maxstack 8
    L_0000: ldstr "foo"
    L_0005: ret 
}
.method private hidebysig instance string bar() cil managed
{
    .maxstack 8
    L_0000: ldstr "bar"
    L_0005: ldsfld string [mscorlib]System.String::Empty
    L_000a: call string [mscorlib]System.String::Concat(string, string)
    L_000f: ret 
}

Приведенные выше ответы технически верны, но то, что вы, возможно, действительно захотите использовать для лучшей читаемости кода и наименьшей вероятности исключения, - это Строка.IsNullOrEmpty(ы)

Я склонен использовать String.Empty вместо того , чтобы "" по одной простой, но неочевидной причине:"" и "" это НЕ одно и то же, в первом из них на самом деле содержится 16 символов нулевой ширины.Очевидно, что ни один компетентный разработчик не собирается вставлять символы нулевой ширины в свой код, но если они туда попадут, это может стать кошмаром для обслуживания.

Примечания:

  • Я использовал U+FEFF в этом примере.

  • Не уверен, что SO будет использовать эти символы, но попробуйте сами с одним из множества символов нулевой ширины

  • Я наткнулся на это только благодаря https://codegolf.stackexchange.com/

Использование String.Empty вместо того , чтобы "".

Это больше для скорости, чем для использования памяти, но это полезный совет.Тот Самый "" является литералом, поэтому будет действовать как литерал:при первом запуске это создал и использует свою ссылку возвращается.Только один экземпляр "" будет сохранен в памяти независимо от того, сколько раз мы им воспользуемся !Я не вижу здесь никаких ограничений на память. Проблема в том, что каждый раз, когда "" используется, выполняется цикл сравнения, чтобы проверить, соответствует ли "" уже включен в список стажеров. На другой стороне, String.Empty является ссылкой на "" хранящийся в Зона памяти .NET Framework. String.Empty указывает на один и тот же адрес памяти для приложений VB.NET и C# .Так зачем же искать ссылку каждый раз, когда вам нужно "" когда у вас есть эта ссылка в String.Empty?

Ссылка: String.Empty против ""

String.Empty не создает объект, в то время как "" создает.Разница, как уже было указано здесь, однако, является тривиальным.

Это просто не имеет значения!

Некоторое прошлое обсуждение этого вопроса:

http://www.codinghorror.com/blog/archives/000185.html

http://blogs.msdn.com/brada/archive/2003/04/22/49997.aspx

http://blogs.msdn.com/brada/archive/2003/04/27/50014.aspx

Все экземпляры "" являются одним и тем же интернированным строковым литералом (или они должны быть такими).Таким образом, вы действительно не будете добавлять новый объект в кучу каждый раз, когда используете "", а просто создадите ссылку на один и тот же интернированный объект.Сказав это, я предпочитаю string .Пустой.Я думаю, это делает код более читабельным.

string mystring = "";
ldstr ""

ldstr помещает новую ссылку на объект в строковый литерал, хранящийся в метаданных.

string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty

ldsfld помещает значение статического поля в стек вычислений

Я склонен использовать String.Empty вместо того, чтобы "" потому что, ИМХО, это понятнее и не так похоже на VB.

Подходя к этому с точки зрения Entity Framework:Похоже, что версии EF 6.1.3 обрабатывают строку.Empty и "" по-разному при проверке.

string.Empty обрабатывается как нулевое значение для целей проверки и выдает ошибку проверки, если оно используется в обязательном (атрибутивном) поле;где как "" пройдет проверку и не выдаст ошибку.

Эта проблема может быть решена в EF 7+.Ссылка:- https://github.com/aspnet/EntityFramework/issues/2610 ).

Редактировать:[Требуется(AllowEmptyStrings = true)] решит эту проблему, разрешив проверку string.Empty.

Поскольку String.Empty не является константой времени компиляции, вы не можете использовать ее в качестве значения по умолчанию в определении функции.

public void test(int i=0,string s="")
    {
      // Function Body
    }

Эрик Липперт написал (17 июня 2013):
"Первым алгоритмом, над которым я когда-либо работал в компиляторе C #, был оптимизатор, который обрабатывает конкатенации строк. К сожалению, мне не удалось перенести эти оптимизации в кодовую базу Roslyn перед уходом;надеюсь, кто-нибудь дойдет до этого!"

Вот некоторые из них Рослин x64 результаты по состоянию на январь 2019 года.Несмотря на согласованные замечания других ответов на этой странице, мне не кажется, что текущий 64-разрядный JIT обрабатывает все эти случаи одинаково, когда все сказано и сделано.

Однако, в частности, обратите внимание, что только один из этих примеров фактически завершается вызовом String.Concat, и я предполагаю, что это по неясным причинам корректности (в отличие от оплошности при оптимизации).Другие различия, по-видимому, объяснить сложнее.


default(строка) + { default(строка), "", Строка.Пусто }

static String s00() => default(String) + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s01() => default(String) + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s02() => default(String) + String.Empty;
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

"" + { default(строка), "", Строка.Пусто }

static String s03() => "" + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s04() => "" + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s05() => "" + String.Empty;
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

Строка.Пусто + { по умолчанию(строка), "", String.Пусто }

static String s06() => String.Empty + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

static String s07() => String.Empty + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

static String s08() => String.Empty + String.Empty;
    mov  rcx,[String::Empty]
    mov  rcx,qword ptr [rcx]
    mov  qword ptr [rsp+20h],rcx
    mov  rcx,qword ptr [rsp+20h]
    mov  rdx,qword ptr [rsp+20h]
    call F330CF60                 ; <-- String.Concat
    nop
    add  rsp,28h
    ret


Детали теста

Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false

Когда вы визуально просматриваете код, "" отображается раскрашенным так, как раскрашиваются строки.строка.Empty выглядит как обычный доступ к классу-члену.При беглом просмотре его легче заметить "" или интуитивно уловить смысл.

Найдите строки (раскрашивание при переполнении стека точно не помогает, но в VS это более очевидно):

var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;

Все присутствующие дали несколько хороших теоретических разъяснений.У меня было похожее сомнение.Поэтому я попробовал использовать базовую кодировку на нем.И я нашел разницу.Вот в чем разница.

string str=null;
Console.WriteLine(str.Length);  // Exception(NullRefernceException) for pointing to null reference. 


string str = string.Empty;
Console.WriteLine(str.Length);  // 0

Таким образом, кажется, что "Null" означает абсолютно пустую строку.Empty" означает, что она содержит какое-то значение, но оно пустое.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top