这两个代码块在功能上是相同的
if (myObj == null)
{
myObj = new MyObj();
}
和
myObj = myObj ?? new MyObj();
但是,使用null合并运算符的那个在myObj不为null的情况下执行不必要的赋值。但后来我想也许编译器可以优化这些自我分配。有没有人知道编译器是否会注意到发生了什么,并且基本上将底部片段转换为顶部片段?
答案 0 :(得分:5)
为了进行比较,我尝试编译两个
object myObj = null;
myObj = myObj ?? new object();
和
object myObj = null;
if(myObject == null)
{
myObj = new object();
}
在Main
方法内部。 (我在Mono 2.6.7上使用MonoDevelop 2.4)
如果代码按预期进行了优化,我们应该会看到生成类似的IL。以下是第一版Main
的IL:
.method public static hidebysig
default void Main (string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
object V_0)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: brtrue IL_000f
IL_0009: pop
IL_000a: newobj instance void object::'.ctor'()
IL_000f: stloc.0
IL_0010: ret
}
和第二个版本:
.method public static hidebysig
default void Main (string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init (
object V_0)
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: brtrue IL_000e
IL_0008: newobj instance void object::'.ctor'()
IL_000d: stloc.0
IL_000e: ret
}
所以第一个版本(使用null-coalescing运算符)产生了更多的IL。
但有两点需要注意:
答案 1 :(得分:3)
刚刚在LinqPad中尝试过:
void Main()
{
MyObj myObj = null;
myObj = myObj ?? new MyObj();
}
这给出了以下IL:
IL_0000: ldnull
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: dup
IL_0004: brtrue.s IL_000C
IL_0006: pop
IL_0007: newobj UserQuery+MyObj..ctor
IL_000C: stloc.0
所以似乎无论stloc.0
是否为null,都会完成赋值(myObj
在IL_000C)...但是JIT可能会稍后优化它。