В чем разница между 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. Я думаю, это делает код более читаемым.
Ответ 11
Это просто не важно!
Некоторое обсуждение этого вопроса:
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
Ответ 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" означает, что он содержит какое-то значение, но он пуст.