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

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

Ответы

Ответ 1

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

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

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

Подробнее см. .NET спецификацию.

Ответ 2

какая разница между String.Empty и "", и они заменяемые

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

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

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

выражение в выражении оператора

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

Ответ 3

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

В соответствии со спецификацией С#, раздел 2.4.4.5: http://msdn.microsoft.com/en-us/library/aa691090(VS.71).aspx

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

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

Таким образом, практический результат "" против String.Empty равен нулю. В итоге JIT выяснит это.

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

Ответ 4

String.Empty - поле readonly, а "" - const. Это означает, что вы не можете использовать String.Empty в инструкции switch, потому что это не константа.

Ответ 5

Другое отличие состоит в том, что String.Empty генерирует более крупный код CIL. Хотя код для ссылок "и String.Empty имеет одинаковую длину, компилятор не оптимизирует конкатенацию строк (см. Eric Lippert сообщение в блоге) для аргументов 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 
}

Ответ 6

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

Ответ 7

Используйте String.Empty а не "".

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

Ссылка: String.Empty vs ""

Ответ 8

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

Ответ 9

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

Примечания:

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

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

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

Ответ 10

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

Ответ 12

string mystring = "";
ldstr ""

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

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

ldsfld толкает значение статического поля в стек оценки

Я предпочитаю использовать String.Empty вместо "", потому что IMHO он более ясный и меньше VB-ish.

Ответ 13

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

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

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

Изменить: [Обязательно (AllowEmptyStrings = true)] разрешит эту проблему, позволяя string.Empty проверять.

Ответ 14

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

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

Ответ 15

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

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

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


default (String) + {default (String), "", String.Empty}

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 (String), "", String.Empty}

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.Empty + {default (String), "", String.Empty}

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

Ответ 16

Когда вы визуально сканируете код, "" выглядит раскрашенным так, как раскрашиваются строки. string.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;

Ответ 17

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

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


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

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