Answers:
在2.0版之前的.NET中,""
创建对象时不string.Empty
创建对象ref,从而string.Empty
提高了效率。
在.NET 2.0版和更高版本中,所有出现的""
引用都指向相同的字符串文字,这意味着""
等效于.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/zh-cn/library/aa691090( VS.71) .aspx
每个字符串文字不一定会导致新的字符串实例。当两个或多个根据字符串相等运算符(第7.9.7节)等效的字符串文字出现在同一程序集中时,这些字符串文字将引用同一字符串实例。
有人甚至在布拉德·艾布拉姆(Brad Abram)的评论中提到了这一点
总之,“”与String.Empty的实际结果为零。准时制将最终解决。
我个人发现,JIT比我聪明得多,因此我尽量不要对此类微编译器优化变得太聪明。与I或C#编译器之前无法预期的那样,JIT将在更合适的时间展开for()循环,更好地删除冗余代码,内联方法等。让JIT做好它的工作:)
String.Empty
是一个只读字段,""
而是const。这意味着您不能String.Empty
在switch语句中使用它,因为它不是常量。
default
关键字的出现,我们可以在不增加可读性的情况下,防止意外修改,并具有编译时常量,尽管老实说,我仍然认为String.Empty比默认值更具可读性,但键入速度较慢
另一个区别是String.Empty生成较大的CIL代码。虽然用于引用“”和String.Empty的代码长度相同,但编译器并未针对String.Empty参数优化字符串连接(请参见Eric Lippert的博客文章)。以下等效功能
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")
上面的答案在技术上是正确的,但是为了获得最佳的代码可读性和最小的机会,您可能真正想使用的是String.IsNullOrEmpty(s)
--foo=$BAR
用来调用您的应用程序,那么您可能想找出它们之间忘记设置环境变量和根本不传递标志的区别。string.IsNullOrEmpty
通常是代码错误,您没有正确验证您的输入或正在做奇怪的事情。当您确实打算使用null
或Maybe / Option类型之类的字词时,通常不应该接受空字符串。
我倾向于使用String.Empty
而不是""
出于一个简单但又不明显的原因:""
而且""
也不尽
相同,第一个实际上有16个零宽度字符。显然,没有合格的开发人员打算将零宽度的字符放入其代码中,但是如果确实能做到这一点,则可能是维护方面的噩梦。
笔记:
在此示例中,我使用了U + FEFF。
不确定SO是否会吃掉这些字符,但是您可以尝试自己尝试使用许多零宽度字符之一
由于https://codegolf.stackexchange.com/,我才遇到这个问题
使用String.Empty
而不是""
。
这不仅是提高速度,还不如占用内存,但这是一个有用的技巧。该
""
是文字,以便将作为文字法:在第一次使用它创建并用于下列用途返回其引用。""
无论我们使用多少次,都只会在内存中存储一个实例!我在这里看不到任何内存损失。问题在于,每次""
使用时,都会执行一个比较循环以检查""
intern池中是否已存在。另一方面,String.Empty
是""
对.NET Framework内存区域中存储的引用。String.Empty
指向VB.NET和C#应用程序的相同内存地址。那么,为什么每次""
都有参考文献时都需要搜索参考文献?String.Empty
?
String.Empty不会创建对象,而“”会创建对象。但是,这里指出的区别是微不足道的。
string mystring = "";
ldstr ""
ldstr
将新的对象引用推送到存储在元数据中的字符串文字。
string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty
ldsfld
将静态字段的值压入评估堆栈
我倾向于使用它,String.Empty
而不是""
因为恕我直言,它更清晰,VB风格更少。
埃里克·利珀特 (Eric Lippert)写道(2013年6月17日):
“我在C#编译器中使用的第一个算法是处理字符串连接的优化器。不幸的是,在离开之前,我没有设法将这些优化移植到Roslyn代码库中;希望有人会做到这一点! ”
这是截至2019年1月的Roslyn x64的一些结果。尽管本页上其他答案的共识,但在我说完所有方法后,当前的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
“” + {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
从实体框架的角度来看:EF版本6.1.3在验证时似乎对String.Empty和“”的对待不同。
string.Empty出于验证目的被视为null值,如果将其用于“必需”(归因)字段,则会抛出验证错误;其中的“”将通过验证,并且不会引发错误。
在EF 7+中可以解决此问题。参考:-https : //github.com/aspnet/EntityFramework/issues/2610)。
编辑:[Required(AllowEmptyStrings = true)]将解决此问题,允许string.Empty进行验证。
当您通过代码直观地进行扫描时,“”会以彩色字符串的方式显示为彩色。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
?