字符串之间的区别是什么。空和""(空字符串)?

在。net中,String.Empty""之间的区别是什么,它们是可交换的,或者是否存在一些围绕相等的潜在引用或本地化问题,String.Empty将确保不是问题?

111815 次浏览

在2.0版本之前的。net中,""创建一个对象,而string.Empty不创建对象__abc3,这使得string.Empty更加高效。

在。net 2.0及以后版本中,所有出现的""都指向相同的字符串字面量,这意味着""相当于.Empty,但仍然不如.Length == 0快。

.Length == 0是最快的选项,但.Empty代码更简洁。

参见.NET规范获取更多信息

字符串。Empty不创建对象,而""创建对象。然而,正如在这里所指出的那样,差异是微不足道的。

""的所有实例都是相同的,被分隔的字符串字面量(或者它们应该是)。因此,每次使用""时,实际上不会在堆上抛出一个新对象,而只是创建一个对相同的内部对象的引用。话虽如此,我还是更喜欢字符串。我认为这使代码更具可读性。

前面的答案对于。net 1.1是正确的(查看他们链接的帖子的日期:2003年)。至于. net 2.0和以后的版本,基本上没有区别。无论如何,JIT最终都会引用堆上相同的对象。

根据c#规范,第2.4.4.5节: http://msdn.microsoft.com/en-us/library/aa691090 (VS.71) . aspx < / p >

每个字符串字面值不一定会产生一个新的字符串实例。当两个或多个根据字符串相等运算符(第7.9.7节)等效的字符串字面值出现在同一个程序集中时,这些字符串字面值引用同一个字符串实例。

有人甚至在布拉德·亚伯拉姆的帖子评论中提到了这一点

综上所述,“;”;与字符串。Empty是nil。JIT最终会弄清楚的。

就我个人而言,我发现JIT比我聪明得多,所以我尽量在微编译器优化方面不太聪明。JIT将展开for()循环,删除冗余代码,内联方法等,在比我或c#编译器之前预期的更好和更合适的时间。让JIT来做它的工作吧:)

上面的答案在技术上是正确的,但你可能真正想要使用的是String.IsNullOrEmpty (s),以获得最好的代码可读性和最小的异常机会

String.Empty是一个只读的字段,而""是一个常量字段。这意味着你不能在switch语句中使用String.Empty,因为它不是一个常量。

字符串之间的区别是什么。空和“”,是他们 可换< / p >

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

另一个区别是字符串。Empty生成更大的CIL代码。而用于引用“”和String的代码。Empty是相同的长度,编译器不会为string优化字符串连接(参见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
}
string mystring = "";
ldstr ""

ldstr将一个新的对象引用推入存储在元数据中的字符串字面量。

string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty

ldsfld将静态字段的值推入计算堆栈

我倾向于使用String.Empty而不是"",因为在我看来,它更清晰,也不那么vb。

我倾向于使用String.Empty而不是"",原因很简单,但并不明显: """"是不一样的,第一个实际上有16个零宽度字符。显然,没有一个有能力的开发人员会在他们的代码中放入零宽度字符,但如果他们真的这样做了,那将是一个维护的噩梦

注:

这里的每个人都给出了很好的理论解释。我也有类似的疑问。所以我尝试了一个基本的编码。我发现了不同之处。区别就在这里。

string str=null;
Console.WriteLine(str.Length);  // Exception(NullRefernceException) for pointing to null reference.




string str = string.Empty;
Console.WriteLine(str.Length);  // 0

因此,“Null”似乎意味着绝对无效&”字符串。“空”表示它包含某种值,但它是空的。

使用__ABC0而不是""

这更多的是为了速度而不是内存使用,但这是一个有用的技巧。的 ""是一个字面量,因此将充当字面量:在第一次使用时,它是 已创建并为以下用途返回其引用。只有一个 ""的实例将存储在内存中,无论多少次 使用它!我没有看到任何内存惩罚。问题是 每次使用""时,都会执行一个比较循环来检查 ""已经在实习生名单中了。在另一边,String.Empty 是对存储在.NET框架内存区中的""的引用。 String.Empty指向VB的相同内存地址。NET和c# 应用程序。所以为什么每次需要""时都要搜索引用呢 当你在String.Empty中有这个引用时?< / p >

参考:__ABC0 vs ""

从实体框架的角度来看:EF版本6.1.3似乎处理字符串。在验证时,Empty和""不同。

字符串。出于验证目的,Empty被视为空值,如果在Required(带属性)字段上使用,则会抛出验证错误;其中as ""将通过验证而不抛出错误。

这个问题可以在EF 7+中解决。参考: - __abc0)。< / p >

编辑:[Required(AllowEmptyStrings = true)]将解决此问题,允许字符串。为空进行验证。

因为字符串。Empty不是编译时常量,不能在函数定义中使用它作为默认值。

public void test(int i=0,string s="")
{
// Function Body
}

Eric Lippert (2013年6月17日):
"我在c#编译器中工作过的第一个算法是处理字符串连接的优化器。不幸的是,在我离开之前,我没有设法将这些优化移植到Roslyn代码库;希望有人能做到!< / em >”

以下是截至2019年1月的一些Roslyn x64结果。尽管本页上的其他答案是一致的,但在我看来,当前的x64 JIT并没有将所有这些情况都一视同仁。

不过要特别注意的是,这些例子中只有一个最终调用了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

字符串。空的,+,{默认(字符串), ",,字符串。空}

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
人力资源> < p > < < / >强测试细节

Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false

当您在视觉上扫描代码时,""会像字符串一样呈现彩色。字符串。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;

谢谢你的回答。

如果我错了,请原谅我的无知。我使用VB,但我认为如果你测试一个未分配的字符串的长度(即IS Nothing),它会返回一个错误。现在,我从1969年开始编程,所以我已经远远落后了,但是我总是通过连接空字符串("")来测试字符串。例:(无论哪种语言):-

if string + "" = ""