前言
在 C# 中,string.Empty
是一个字段,表示空字符串。但是其与 ""
的区别对我来说并不是很清楚,
因此我决定使用 IL 帮助我分清其中的区别。
编写与反编译
编写实例
我通过了编写一个很简单的方法来实现了这个过程
1
2
3
4
5
6
7
8
9
10
11
| namespace ClassLibrary1;
public class Class1
{
public static string StaticMethod()
{
var a = "";
var b = string.Empty;
return a;
}
}
|
为了区分普通方法和静态方法中可能存在的差异性,我选择编写了两个方法 Method
和 StaticMethod
。
反编译
感谢 Rider,我们才可以如此轻松的查看 IL 代码。我把整个的 IL 都会贴出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| .class public auto ansi beforefieldinit
ClassLibrary1.Class1
extends [System.Runtime]System.Object
{
.method public hidebysig static string
StaticMethod() cil managed
{
.custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor([in] unsigned int8)
= (01 00 01 00 00 ) // .....
// unsigned int8(1) // 0x01
.maxstack 8
// [7 9 - 7 20]
IL_0000: ldstr ""
// [8 9 - 8 30]
IL_0005: ldsfld string [System.Runtime]System.String::Empty
IL_000a: pop
// [9 9 - 9 18]
IL_000b: ret
} // end of method Class1::StaticMethod
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8
IL_0000: ldarg.0 // this
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
} // end of method Class1::.ctor
} // end of class ClassLibrary1.Class1
|
分析
为了简洁,我们只分析 StaticMethod
中最核心的部分:
1
2
3
4
5
6
7
8
9
| // [7 9 - 7 20]
IL_0000: ldstr ""
// [8 9 - 8 30]
IL_0005: ldsfld string [System.Runtime]System.String::Empty
IL_000a: pop
// [9 9 - 9 18]
IL_000b: ret
|
对于 ""
通过 IL 可以发现其是直接通过 ldstr
直接装载了 ""
字符串进入栈顶。而 string.Empty
则是通过 ldsfld
装载了在 [System.Runtime]System.String::Empty
的 string
。
通常来说,ldsfld
是直接装载值,而 ldsflda
才是装载一个地址。因此对于使用 string.Empty
和 ""
在装载性能上的差异性几乎是毫无差别。
那真的没有差别了吗?
在性能上的差别已经被排除,那是否它们真的没有差别呢?答案是否定的。考虑如下代码
1
2
3
4
5
| var m = str switch
{
"" => "A",
string.Empty => "B"
};
|
或者
1
2
3
4
5
6
7
8
9
10
11
| string str = "";
string m;
switch(str)
{
case "":
m = "A";
break;
case string.Empty:
m = "B";
break;
}
|
其中所有 string.Empty
上都会引发错误 [CS0150] A constant value is expected
。
其中核心原因可以通过直接反编译 string.Empty
发现其的签名是 public static readonly string Empty;
而 ""
则是 const
。
总结
对于 ""
和 string.Empty
,两者几乎不存在性能差异,唯一差别只存在于前者是常量而后者仅为只读静态字段。
而在使用中我更推荐使用 ""
,因为其会带来更好的可读性。
Author
KevinZonda
LastMod
2022-05-02
(5509e05)