В чем разница между String.Empty и "" (пустая строка)?
В.NET какая разница между String.Empty
а также ""
и являются ли они взаимозаменяемыми, или существуют какие-то основные проблемы с ссылками или локализацией, связанные с равенством String.Empty
обеспечит не проблема?
19 ответов
В.NET до версии 2.0, ""
создает объект в то время как string.Empty
не создает объект ref, который делает 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
}
Выражение регистра в операторе 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(VS.71).aspx
Каждый строковый литерал не обязательно приводит к новому экземпляру строки. Когда два или более строковых литерала, эквивалентных по оператору равенства строк (раздел 7.9.7), появляются в одной сборке, эти строковые литералы ссылаются на один и тот же экземпляр строки.
Кто-то даже упоминает об этом в комментариях к посту Брэда Абрама
Таким образом, практический результат "" против String.Empty равен нулю. JIT выяснит это в конце.
Лично я обнаружил, что JIT намного умнее меня, и поэтому я стараюсь не слишком умничать с такими оптимизациями микрокомпилятора. JIT развернется для циклов (), удалит избыточный код, встроенные методы и т. Д. Лучше и в более подходящее время, чем когда-либо мог ожидать компилятор I или C#. Пусть JIT сделает свое дело:)
String.Empty
поле только для чтения, в то время как ""
является постоянным Это означает, что вы не можете использовать String.Empty
в операторе switch, потому что он не является константой.
Я склонен использовать String.Empty
скорее, чем ""
по одной простой, но не очевидной причине:""
а также ""
НЕ одинаковы, первый фактически содержит 16 символов нулевой ширины. Очевидно, что ни один компетентный разработчик не собирается добавлять символы нулевой ширины в свой код, но если они туда попадут, это может стать кошмаром обслуживания.
Заметки:
Я использовал U+FEFF в этом примере.
Не уверен, что SO будет есть эти символы, но попробуйте сами с одним из множества символов нулевой ширины.
Я только столкнулся с этим благодаря https://codegolf.stackexchange.com/
Другое отличие состоит в том, что String.Empty генерирует больший код CIL. Хотя код для ссылки "" и String.Empty имеет одинаковую длину, компилятор не оптимизирует конкатенацию строк (см. Сообщение в блоге Эрика Липперта) для аргументов 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
}
Приведенные выше ответы технически правильны, но то, что вы действительно хотите использовать для лучшей читабельности кода и наименьшей вероятности исключения, - это String.IsNullOrEmpty(s)
использование 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
string mystring = "";
ldstr ""
ldstr
выдвигает новую ссылку на объект на строковый литерал, хранящийся в метаданных.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
помещает значение статического поля в стек оценки
Я склонен использовать String.Empty
вместо ""
потому что имхо это понятнее и меньше VB-иш.
Эрик Липперт написал (17 июня 2013 г.):
"Первым алгоритмом, над которым я когда-либо работал в компиляторе C#, был оптимизатор, который обрабатывает конкатенации строк. К сожалению, мне не удалось перенести эти оптимизации в кодовую базу Roslyn до того, как я ушел; надеюсь, кто-то доберется до этого!
Вот некоторые результаты Roslyn x64 по состоянию на январь 2019 года. Несмотря на консенсусные замечания других ответов на этой странице, мне не кажется, что текущий JIT x64 рассматривает все эти случаи одинаково, когда все сказано и сделано.
Обратите внимание, в частности, однако, что только один из этих примеров фактически вызывает String.Concat
и я предполагаю, что это из-за неясных причин правильности (в отличие от надзора за оптимизацией). Другие различия, кажется, труднее объяснить.
по умолчанию (строка) +...
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
"" +...
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 +...
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
Когда вы визуально просматриваете код, "" становится раскрашенным так же, как раскрашены строки. 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;
Поскольку String.Empty не является константой времени компиляции, вы не можете использовать ее в качестве значения по умолчанию в определении функции.
public void test(int i=0,string s="")
{
// Function Body
}
Исходя из этого, с точки зрения Entity Framework: версии EF 6.1.3, по-видимому, обрабатывают String.Empty и "" по-разному при проверке.
string.Empty обрабатывается как нулевое значение для целей проверки и выдает ошибку проверки, если она используется в поле Required (приписывается); где как "" пройдет валидацию и не выдаст ошибку.
Эта проблема может быть решена в EF 7+. Ссылка: - https://github.com/aspnet/EntityFramework/issues/2610).
Редактировать: [Обязательный (AllowEmptyStrings = true)] решит эту проблему, позволив string.Empty для проверки.
Используйте в большинстве случаев для удобства чтения. Видение некоторых разработчиков может быть не в состоянии определить разницу между и" "
, гдеstring.Empty
чисто.
Для параметров по умолчанию все равно придется использовать""
, но в таком случае мне интересно, почему метод не используетstring? = null
вместо этого для параметра по умолчанию. (также более читабельно для слабовидящих)
Спасибо за очень информативный ответ.
Простите мое незнание, если я ошибаюсь. Я использую VB, но я думаю, что если вы проверите длину неназначенной строки (например, IS Nothing), она вернет ошибку. Я начал программировать в 1969 году, так что я сильно отставал, однако я всегда тестировал строки, объединяя пустую строку (""). Например (на любом языке): -
if string + "" = ""
Все здесь дали некоторые хорошие теоретические разъяснения. У меня было подобное сомнение. Поэтому я попробовал базовую кодировку на нем. И я нашел разницу. Вот в чем разница.
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" означает, что оно содержит какое-то значение, но оно пустое.