假设A 是一个引用类型并且这段代码在一个方法中:
A a = new A(); 将始终在堆上创建一个新对象,并为a 分配对该新对象的引用。
A a = null; 和 A a; 都会将 null 分配给 a。
但是,与 A a; 相比,为 A a = null; 生成的 IL 可能有所不同
考虑以下简单程序:
static void Main()
{
string s;
if (Environment.TickCount > 0)
s = "A";
else
s = "B";
Console.WriteLine(s);
}
为发布构建生成的 IL 如下所示:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] string s)
L_0000: call int32 [mscorlib]System.Environment::get_TickCount()
L_0005: ldc.i4.0
L_0006: ble.s L_0010
L_0008: ldstr "A"
L_000d: stloc.0
L_000e: br.s L_0016
L_0010: ldstr "B"
L_0015: stloc.0
L_0016: ldloc.0
L_0017: call void [mscorlib]System.Console::WriteLine(string)
L_001c: ret
}
现在修改代码以初始化对 null 的引用:
static void Main()
{
string s = null;
if (Environment.TickCount > 0)
s = "A";
else
s = "B";
Console.WriteLine(s);
}
IL 变成了这样:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 2
.locals init (
[0] string s)
L_0000: ldnull <====== Lookie here
L_0001: stloc.0 <====== and here
L_0002: call int32 [mscorlib]System.Environment::get_TickCount()
L_0007: ldc.i4.0
L_0008: ble.s L_0012
L_000a: ldstr "A"
L_000f: stloc.0
L_0010: br.s L_0018
L_0012: ldstr "B"
L_0017: stloc.0
L_0018: ldloc.0
L_0019: call void [mscorlib]System.Console::WriteLine(string)
L_001e: ret
请注意,已经生成了两条新的 IL 指令来将变量初始化为 null(尽管据我所知,.locals init ([0] string s) 已经将其初始化为 null)。
JIT 编译器很可能会对此进行优化,但在生成的 IL 代码方面肯定存在差异。
(为了简单起见,我在此示例中使用了string,但如果您使用自己的类,也会发生同样的情况。)