String.Empty与""(空字符串)之间有什么区别?

344
在.NET中,String.Empty""有什么区别?它们是否可以互换使用,或者在相等性方面是否存在基础引用或本地化问题,String.Empty可以确保这些问题不会成为问题?

5
真正的问题不是“什么”,而是“为什么”。为什么 Microsoft 提出了 string.Empty,并且为什么将其声明为 readonly 而不是 const,背后的原因是什么。 - user1451111
几个答案似乎是针对检查字符串是否为空的,这是一个比通常使用空字符串更具体的问题。 - Stewart
这个回答解决了你的问题吗?在C#中,初始化字符串应该使用string.Empty还是String.Empty还是""? - Michael Freidgeim
19个回答

5

7
请将文本翻译成中文。仅返回翻译后的文本:请包含一些内联解释。 - László Papp

4
string mystring = "";
ldstr ""

ldstr指令会将存储在元数据中的字符串字面量推送到新的对象引用中。

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

ldsfld将静态字段的值推送到评估堆栈上。

我倾向于使用String.Empty而不是"",因为我认为它更清晰,不那么像VB语言。


3
当您目视代码时,"" 的颜色会像字符串一样被着色。string.Empty看起来像是一个普通的类成员访问。在快速浏览中,更容易发现 "" 或直观理解其含义。
找出这些字符串(stack overflow的着色并不十分明显,但在VS中则更为明显):
var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;

3
你说得很有道理,但开发人员真的是这个意思吗?也许他们本来想输入一些未知的值,然后忘记返回了?string.Empty的好处在于能够确保原作者真正想要使用string.Empty。我知道这只是一个小细节。 - mark_h
此外,一个恶意的(或者是粗心的)开发者可能会在引号之间添加一个零宽字符,而不是使用适当的转义序列例如 \u00ad - Palec

3

Eric Lippert 写道(2013年6月17日):
“我在C#编译器上处理字符串连接的优化算法是我曾经处理过的第一个算法。不幸的是,在我离开之前,我没有将这些优化移植到Roslyn代码库中; 希望有人能够做到这一点!”

以下是截至2019年1月的一些Roslyn x64结果。尽管本页其他答案的共识意见是相同的,但在我的看来,当前的x64 JIT并未将所有这些情况视为相同,毕竟如此。

请特别注意,这些示例中只有一个实际上会调用String.Concat,我猜测这是出于晦涩的正确性原因(而不是优化失误)。其他差异似乎更难解释。


default(String) + { default(String), "", String.Empty }

默认值(String)+ { 默认值(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 }

空字符串 + { 默认(String), "", 空字符串 }
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

使用 sharplab.io 进行快速检查后发现,Core CLR 6.0.21.52210 将 s00 到 s07 视为相同(生成的代码与此处的 s00 匹配),但仍然对 s08 使用 String.Concat()。 - Zastai

3

由于String.Empty不是编译时常量,因此您不能在函数定义中将其用作默认值。

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

2
这个方法:public void test(int i=0, string s=string.Empty) {} 中的摘要会编译失败,并提示 "Default parameter value for 's' must be a compile-time constant"。OP 的答案是可行的。 - bugybunny

2
从 Entity Framework 的角度来看:EF 版本 6.1.3 在验证时似乎会将 String.Empty 和 "" 区别对待。
对于验证目的,string.Empty 被视为 null 值,如果在 Required(属性)字段上使用它,则会抛出验证错误;而 "" 将通过验证并且不会抛出错误。
这个问题可能在 EF 7+ 中得到解决。参考: - https://github.com/aspnet/EntityFramework/issues/2610)。
编辑:[Required(AllowEmptyStrings = true)] 可以解决此问题,允许 string.Empty 进行验证。

0
在大多数情况下,为了可读性,请使用string.Empty。有些开发人员可能无法区分""" ",而string.Empty则很清晰。
对于参数默认值仍需使用"",但在这种情况下,我想知道为什么方法不使用string?= null来代替默认参数(对于视力受损者也更易读)。

-1

非常感谢您提供的信息丰富的答案。

如果我错了,请原谅我的无知。我正在使用VB,但我认为如果您测试未分配字符串的长度(即IS Nothing),它会返回错误。现在,我从1969年开始编程,所以我已经被远远落下了,但是我一直通过连接空字符串(“”)来测试字符串。例如(用任何语言):-

if string + "" = ""


-12

这里的每个人都提供了一些很好的理论解释。我有一个类似的疑问。所以我尝试了一些基本的编码,并发现了一个区别。以下是这个区别。

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”表示它包含某种值,但是为空。


9
请注意,该问题涉及""string.Empty的区别。仅在尝试确定字符串是否为空时,才提到了null - Palec

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接