在。net中,String和。net之间的区别是什么?空和"",他们是可交换的,或者有一些潜在的引用或本地化问题,围绕相等的字符串。空将保证都不是问题?


当前回答

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

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

这个问题可以在EF 7+中解决。参考: - https://github.com/aspnet/EntityFramework/issues/2610)。

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

其他回答

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

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

注:

在这个例子中,我使用了U+FEFF。 不确定SO是否会吃掉这些字符,但请自己尝试使用许多零宽度字符中的一个 多亏了https://codegolf.stackexchange.com/,我才发现了这一点

前面的答案对于。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是nil。JIT最终会弄清楚的。

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

Eric Lippert写道(2013年6月17日):“我在c#编译器中工作过的第一个算法是处理字符串连接的优化器。不幸的是,在我离开Roslyn之前,我没有设法将这些优化移植到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

另一个区别是字符串。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 
}