В .NET, в чем разница между String.Empty
и ""
, и являются ли они взаимозаменяемыми, или есть какие-то базовые ссылки или проблемы с локализацией, связанные с равенством, которые String.Empty
гарантируют, что это не проблема?
В чем разница между String.Empty и (пустой строкой)?
Ответы (18)
В .NET до версии 2.0 ""
создает объект, а string.Empty
не создает объекта ref, что делает string.Empty
более эффективным.
В версии 2.0 и более поздних версиях .NET все вхождения ""
относятся к одному и тому же строковому литералу, что означает, что ""
эквивалентно .Empty
, но все же не так быстро, как .Length == 0
.
.Length == 0
- самый быстрый вариант, но .Empty
позволяет получить немного более чистый код.
Дополнительную информацию см. В спецификации .NET.
string.IsNullOrEmpty( stringVar )
.
- person Flynn1179; 27.08.2015
в чем разница между 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
String.Empty
в качестве аргумента. Вы правы в том, что все примеры показывают это you simply can't put a (run-time) "value" into (compile-time) metadata
, и именно это и стремятся показать примеры.
- person Sasuke Uchiha; 04.06.2020
Предыдущие ответы были правильными для .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), появляются в одной сборке, эти строковые литералы относятся к одному и тому же экземпляру строки.
Кто-то даже упоминает об этом в комментариях к посту Брэда Абрама.
Таким образом, практический результат "" vs. String.Empty равен нулю. В конце концов, JIT разберется.
Лично я обнаружил, что JIT намного умнее меня, и поэтому я стараюсь не слишком умничать с подобными оптимизациями микрокомпиляторов. JIT будет разворачивать циклы for (), удалять избыточный код, встроенные методы и т. Д. Лучше и в более подходящее время, чем я или компилятор C # могли когда-либо предвидеть. Пусть JIT сделает свое дело :)
String.Empty
- это поле только для чтения, а ""
- const. Это означает, что вы не можете использовать String.Empty
в операторе switch, потому что он не является константой.
default
мы можем повысить удобочитаемость без него, предотвратить случайное изменение и иметь константу времени компиляции, хотя, честно говоря, я по-прежнему считаю String.Empty более читабельным, чем по умолчанию, но медленнее для ввода
- person Enzoaeneas; 11.02.2020
default
пуста, а не пуста. default
ко всем ссылочным объектам имеет значение NULL.
- person Sorensen; 18.09.2020
Другое отличие состоит в том, что 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
}
"bar " + (ok ? "" : "error")
- person symbiont; 29.01.2019
ok
не является константой времени компиляции, результирующий IL все равно должен будет использовать string.Concat.
- person Sorensen; 18.09.2020
Я предпочитаю использовать String.Empty
, а не ""
по одной простой, но не очевидной причине: ""
и ""
НЕ одно и то же, первый фактически содержит 16 символов нулевой ширины. Очевидно, что ни один компетентный разработчик не собирается вставлять символы нулевой ширины в свой код, но если они все же попадут туда, это может стать кошмаром для обслуживания.
Примечания:
В этом примере я использовал U + FEFF.
Не уверен, что SO собирается съесть эти символы, но попробуйте сами с одним из множества символов нулевой ширины.
Я обнаружил это только благодаря https://codegolf.stackexchange.com/
Вышеупомянутые ответы технически верны, но то, что вы действительно можете использовать для лучшей читаемости кода и наименьшей вероятности исключения, - это String.IsNullOrEmpty (s)
--foo=$BAR
, тогда вы, вероятно, захотите заметить разницу между ними, которые забывают установить env var, и они вообще не передают флаг. string.IsNullOrEmpty
часто свидетельствует о том, что вы неправильно проверили вводимые данные или делаете странные вещи. Обычно вам не следует принимать пустые строки, когда вы действительно хотите использовать null
или что-то вроде типа Maybe / Option.
- person Alastair Maw; 23.10.2018
Используйте String.Empty
вместо ""
.
Это больше для скорости, чем использования памяти, но это полезный совет.
""
- это литерал, поэтому он будет действовать как литерал: при первом использовании он создается, а для следующих применений возвращается его ссылка. В памяти будет храниться только один экземпляр""
независимо от того, сколько раз мы его используем! Я не вижу здесь штрафов за память. Проблема в том, что каждый раз, когда используется""
, выполняется цикл сравнения, чтобы проверить, находится ли""
уже в внутреннем пуле. С другой стороны,String.Empty
является ссылка на""
, хранящийся в зоне памяти .NET Framework.String.Empty
указывает на один и тот же адрес памяти для приложений VB.NET и C #. Так зачем искать ссылку каждый раз, когда вам нужно""
, когда она есть вString.Empty
?
Ссылка: String.Empty
vs ""
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 mystring = "";
ldstr ""
ldstr
подталкивает новую ссылку на объект к строковому литералу, хранящемуся в метаданных.
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
помещает значение статического поля в стек оценки
Я предпочитаю использовать String.Empty
вместо ""
, потому что, IMHO, он более понятен и менее VB-иш.
Когда вы визуально просматриваете код, "" становится раскрашенным так же, как раскрашены строки. 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;
\u00ad
.
- person Palec; 18.05.2019
Эрик Липперт написал (17 июня 2013 г.):
« Первым алгоритмом, над которым я когда-либо работал в компиляторе C #, был оптимизатор, который обрабатывает конкатенации строк. К сожалению, мне не удалось перенести эти оптимизации в кодовую базу Roslyn перед тем, как я ушел; надеюсь, кто-нибудь дойдет до этого! "
Вот некоторые результаты Roslyn x64 по состоянию на январь 2019 года. Несмотря на согласованные замечания по другим ответам на этой странице, мне не кажется, что текущая JIT x64 обрабатывает все эти случаи одинаково, когда все сказано и сделано.
Однако обратите внимание, в частности, что только один из этих примеров фактически вызывает String.Concat
, и я предполагаю, что это из соображений неясной правильности (в отличие от надзора за оптимизацией). Остальные различия объяснить сложнее.
по умолчанию (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
"" + {по умолчанию (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 + {по умолчанию (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
Исходя из этого с точки зрения Entity Framework: EF версии 6.1.3, похоже, по-разному обрабатывают String.Empty и "" при проверке.
string.Empty обрабатывается как нулевое значение для целей проверки и выдаст ошибку проверки, если оно используется в обязательном (атрибутированном) поле; где "" пройдет проверку и не выдаст ошибку.
Эта проблема может быть решена в EF 7+. Ссылка: - https://github.com/aspnet/EntityFramework/issues/2610 ).
Изменить: [Required (AllowEmptyStrings = true)] решит эту проблему, разрешив проверку string.Empty.
Поскольку String.Empty не является константой времени компиляции, вы не можете использовать ее в качестве значения по умолчанию в определении функции.
public void test(int i=0,string s="")
{
// Function Body
}
public void test(int i=0, string s=string.Empty) {}
не будет компилироваться и скажет, что значение параметра по умолчанию для 's' должно быть константой времени компиляции. Ответ OP работает.
- person bugybunny; 26.10.2018
Спасибо за очень информативный ответ.
Простите мое незнание, если я ошибаюсь. Я использую 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» означает абсолютно пустое значение, а «String.Empty» означает, что он содержит какое-то значение, но он пуст.
""
по сравнению с string.Empty
. Только при попытке определить, пуста ли строка, было упомянуто null
.
- person Palec; 22.01.2016
string.Empty
и что послужило основанием для объявления его какreadonly
вместоconst
. - person user1451111   schedule 07.07.2018