String.Empty和“”(空字符串)有什么区别?

时间:2008-09-30 01:59:47

标签: .net double-quotes string

在.NET中,String.Empty""之间有什么区别,它们是可互换的,还是存在String.Empty确保不存在的相等的基础参考或本地化问题一个问题?

18 个答案:

答案 0 :(得分:275)

在版本2.0之前的.NET中,""创建了一个对象,而string.Empty没有创建对象 ref ,这使得string.Empty更有效率。

在.NET 2.0及更高版本中,所有出现的""引用相同的字符串文字,这意味着""等同于.Empty,但仍然不如.Length == 0快{1}}。

.Length == 0是最快的选项,但.Empty会使代码更清晰。

请参阅.NET specification for more information

答案 1 :(得分:182)

  

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
}

开关语句中的案例表达

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

答案 2 :(得分:38)

以前的答案对于.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#编译器可以预先预测的更合适的时间。让JIT完成它的工作:)

答案 3 :(得分:35)

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

答案 4 :(得分:18)

另一个区别是String.Empty会生成更大的CIL代码。虽然引用“”和String.Empty的代码长度相同,但编译器不会针对String.Empty参数优化字符串连接(请参阅Eric Lippert的blog post)。以下等效函数

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 
}

答案 5 :(得分:13)

上述答案在技术上是正确的,但您可能真正想要使用的是,为了获得最佳代码可读性和最少的异常机会,String.IsNullOrEmpty(s)

答案 6 :(得分:8)

使用String.Empty而不是""

  

这比速度比内存使用更多,但它是一个有用的提示。该   ""是一个文字,所以它将作为一个文字:在第一次使用它时   创建并为以下用途返回其引用。只有一个   无论我们多少次,""的实例都将存储在内存中   用它!我没有看到任何记忆惩罚。 问题在于   每次使用""时,都会执行比较循环以检查是否存在   ""已经在实习池中。 另一方面,String.Empty   是对存储在 .NET Framework内存区域中的""的引用。   String.Empty指向VB.NET和C#的相同内存地址   应用。那么为什么每次需要时都会搜索引用""   当你在String.Empty中有这个参考时?

参考:String.Empty vs ""

答案 7 :(得分:7)

String.Empty不会创建对象,而“”会创建对象。然而,正如here所指出的那样,差异是微不足道的。

答案 8 :(得分:6)

“”的所有实例都是相同的,实际的字符串文字(或它们应该是)。因此,每次使用“”时,你真的不会在堆上抛出一个新对象,而只是创建对同一个实体对象的引用。话虽如此,我更喜欢string.Empty。我认为它使代码更具可读性。

答案 9 :(得分:6)

我倾向于使用String.Empty而不是""来解决一个简单但不明显的原因: """"不相同,第一个实际上有16个零宽度字符。显然没有一个有能力的开发人员会在他们的代码中放入零宽度字符,但如果他们确实进入那里,那么这可能是一个维护噩梦。

注意:

答案 10 :(得分:5)

答案 11 :(得分:4)

string mystring = "";
ldstr ""

ldstr将新对象引用推送到存储在元数据中的字符串文字。

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

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

我倾向于使用String.Empty代替"",因为恕我直言,它更清晰,更少VB-ish。

答案 12 :(得分:2)

从实体框架的角度出发:EF版本6.1.3似乎处理String.Empty和""验证时有所不同。

string.Empty被视为用于验证目的的空值,如果它在必需(属性)字段中使用,则会抛出验证错误; as""将通过验证而不是抛出错误。

此问题可能在EF 7+中得到解决。参考: - https://github.com/aspnet/EntityFramework/issues/2610)。

编辑:[必需(AllowEmptyStrings = true)]将解决此问题,允许string.Empty进行验证。

答案 13 :(得分:2)

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

def doubler(n):
    x = 1
    while x < n:
        yield x
        x *= 2


for i in doubler(100):
    print(i)

答案 14 :(得分:1)

  

<子>的埃里克利珀 wrote(2013年6月17日):
“我所制作在C#编译器是优化的第一算法,处理字符串串联不幸的是,在离开之前,我没有设法将这些优化移植到Roslyn代码库中;希望有人能做到这一点!”

下面是一些罗斯林64 结果2019年一月尽管此页面上的其他答案的共识的话,它不会出现,我认为当前的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

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

答案 15 :(得分:1)

以可视方式扫描代码时,“”会以彩色字符串的方式呈现彩色。 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;

答案 16 :(得分:0)

感谢您提供非常有用的答案。

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

if string + "" = ""

答案 17 :(得分:-4)

这里的每个人都给出了一些很好的理论澄清。我有类似的疑问。所以我尝试了一个基本的编码。我发现了一个区别。这就是区别。

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


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

所以看来&#34; Null&#34;意味着绝对无效&amp; &#34;的String.Empty&#34;意味着它包含某种值,但它是空的。