These two code blocks are functionally the same
if (myObj == null)
{
myObj 开发者_如何学JAVA= new MyObj();
}
and
myObj = myObj ?? new MyObj();
However, the one using the null coalescing operator does an unnecessary assignment in the case where myObj is not null. But then I thought maybe the compiler optimizes these self assignments. Does anyone know if the compiler will notice what is going on and essentially convert the bottom snippet into the top one?
For comparison purposes, I tried compiling both
object myObj = null;
myObj = myObj ?? new object();
and
object myObj = null;
if(myObject == null)
{
myObj = new object();
}
inside of the Main
method. (I am using MonoDevelop 2.4 on Mono 2.6.7)
If the code were optimized as expected, we should see similar IL being generated. Here is the IL for the first version of Main
:
.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
}
and for the second version:
.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
}
So the first version (using the null-coalescing operator) has generated slightly more IL.
But there are two things to note about this:
- This IL is what I got using MoveDevelop - if you compile it in Visual Studio, it could very well have been a different story. Perhaps it is optimized in Microsoft's with compiler. And even if it's the same with them, another person's compiler could easily optimize this. Just because something holds for some compilers, doesn't mean you would expect it from everybody's compiler.
- The CLR makes use of a JIT. Even if this wasn't optimized at compile-time, it probably would have been optimized at run-time. In fact, this may very well be why the compile isn't so concerned about such a micro-optimization.
Just tried it in LinqPad:
void Main()
{
MyObj myObj = null;
myObj = myObj ?? new MyObj();
}
This gives the following 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
So it seems the assignment (stloc.0
at IL_000C) is done whether or not myObj
was null... but perhaps the JIT optimizes this later.
精彩评论