Відповіді:
У .NET до версії 2.0 ""
створює об'єкт, при цьому string.Empty
не створює реферу об'єкта , що робить string.Empty
більш ефективним.
У версії 2.0 і більш пізньої .NET все входження ""
відносяться до однієї і тієї ж рядки литерала, що означає , що ""
еквівалентно .Empty
, але все ж не так швидко , як .Length == 0
.
.Length == 0
є найшвидшим варіантом, але .Empty
робить трохи більш чистим код.
string.IsNullOrEmpty( stringVar )
.
яка різниця між 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
що саме так і мають на меті показати приклади.
Попередні відповіді були правильними для .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 розгорнуться для () циклів, видалить надлишковий код, вбудовані методи тощо і краще, і в більш підходящий час, ніж будь-який я або компілятор C # коли-небудь міг передбачити до початку. Нехай СІТ виконує свою роботу :)
String.Empty
є полем для читання лише в той час ""
, як const . Це означає, що ви не можете використовувати String.Empty
в операторі перемикання, оскільки це не константа.
default
ключового слова ми можемо сприяти читанню без запобігання випадкових модифікацій та постійної тривалості компіляції, хоча чесно кажучи, я все-таки думаю, що String.Empty читабельніше, ніж за замовчуванням, але повільніше
Ще одна відмінність полягає в тому, що String.Empty генерує більший код CIL. Хоча код для посилань на "" і String.Empty має однакову довжину, компілятор не оптимізує об'єднання рядків (див. Допис у блозі Еріка Ліпперта ) для аргументів String.Empty. Наступні еквівалентні функції
string foo()
{
return "foo" + "";
}
string bar()
{
return "bar" + string.Empty;
}
генерують цю ІЛ
.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")
Наведені вище відповіді технічно правильні, але те, що ви, можливо, хочете використовувати, для кращої читабельності коду та найменшого шансу на виняток - це String.IsNullOrEmpty (s)
--foo=$BAR
ви, ймовірно, хочете помітити різницю між ними, забувши встановити env var, і вони взагалі не передають прапор. string.IsNullOrEmpty
часто кодовий запах, який ви не підтвердили належним чином або робите дивні речі. Як правило, ви не повинні приймати порожні рядки, коли ви дійсно маєте намір використовувати null
, або щось на зразок типу "Можливо / Опція".
Я, як правило, використовую String.Empty
не ""
одну просту, але не очевидну причину:
""
і ""
НЕ є однаковою, перша - насправді 16 символів нульової ширини. Очевидно, жоден грамотний розробник не збирається вводити символи нульової ширини у свій код, але якщо вони все-таки потраплять туди, це може бути кошмаром технічного обслуговування.
Примітки:
Я використовував U + FEFF в цьому прикладі.
Не впевнений, чи ТАК їсть цих персонажів, але спробуйте сам із одним із багатьох символів нульової ширини
Я натрапив на це лише завдяки https://codegolf.stackexchange.com/
Використовуйте, String.Empty
а не ""
.
Це швидше, ніж швидкість використання пам'яті, але це корисна порада. Літерал
""
є таким чином, він буде діяти як буквальний: при першому використанні він створюється, а для наступних застосувань повертається його посилання.""
У пам'яті буде збережено лише один екземпляр незалежно від того, скільки разів ми ним користуємося! Я не бачу жодних штрафних санкцій за пам'ять. Проблема полягає в тому, що кожного разу, коли""
використовується цикл, виконується порівняльний цикл, щоб перевірити, чи""
вже він знаходиться у пулі стажування. З іншого бокуString.Empty
- це посилання на""
збережену в зоні пам'яті .NET Framework .String.Empty
вказує на ту саму адресу пам'яті для програм VB.NET та C #. То навіщо шукати посилання кожного разу, коли вам потрібно ?""
коли вам коли у вас є посиланняString.Empty
Довідка: String.Empty
vs""
Усі екземпляри "" є однаковими, інтернованими рядковими буквами (або вони повинні бути). Таким чином, ви дійсно не будете кидати новий об’єкт на купу щоразу, коли використовуєте "", а просто створюєте посилання на той самий інтернований об'єкт. Сказавши це, я віддаю перевагу 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
замість того, ""
що IMHO зрозуміліший і менш VB-ish.
Ерік Ліпперт писав (17 червня 2013 р.):
"Першим алгоритмом, над яким я працював у компіляторі C #, був оптимізатор, який обробляє рядкові конкатекації. На жаль, мені не вдалося перенести ці оптимізації до кодової бази Рослін; сподіваюся, хтось діставайся до цього! "
Ось деякі результати Roslyn x64 станом на січень 2019 року. Незважаючи на консенсусні зауваження інших відповідей на цій сторінці, мені не здається, що поточний x64 JIT трактує всі ці випадки однаково, коли все сказано і зроблено.
Однак, зауважте, що лише один із цих прикладів насправді закінчує дзвінки 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
"" + {за замовчуванням (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 та "" по-різному під час перевірки.
рядок.Empty вважається нульовим значенням для цілей перевірки, і він видасть помилку перевірки, якщо він буде використаний у полі Потрібне (атрибутивне); де як "" пройде перевірку і не видасть помилку.
Ця проблема може бути вирішена в EF 7+. Довідка: - https://github.com/aspnet/EntityFramework/isissue/2610 ).
Редагувати: [Обов’язково (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" повинно бути константою часу компіляції. Відповідь ОП працює.
Коли ви візуально скануєте код, "" з'являється кольоровим способом кольорових рядків. 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
.
Тут усі дали гарне теоретичне уточнення. У мене були подібні сумніви. Тому я спробував базове кодування на ньому. І я знайшов різницю. Ось різниця.
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
.
string.Empty
і що було обґрунтуванням декларування цього якreadonly
замістьconst
.