编译器在用于自我分配时是否优化Null Coalescing运算符?

Jer*_*eir 9 .net c#-4.0

这两个代码块在功能上是相同的

if (myObj == null)
{
    myObj = new MyObj();
}
Run Code Online (Sandbox Code Playgroud)

myObj = myObj ?? new MyObj();
Run Code Online (Sandbox Code Playgroud)

但是,使用null合并运算符的那个在myObj不为null的情况下执行不必要的赋值.但后来我想也许编译器可以优化这些自我分配.有谁知道编译器是否会注意到正在发生的事情并且基本上将底部片段转换为顶部片段?

Ken*_*nde 5

为了进行比较,我尝试编译两者

object myObj = null;
myObj = myObj ?? new object();
Run Code Online (Sandbox Code Playgroud)

object myObj = null;
if(myObject == null)
{
  myObj = new object();
}
Run Code Online (Sandbox Code Playgroud)

Main方法内部.(我在Mono 2.6.7上使用MonoDevelop 2.4)

如果代码按预期进行了优化,我们应该会看到生成类似的IL.这是第一个版本的IL 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 
}
Run Code Online (Sandbox Code Playgroud)

而对于第二个版本:

.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 
}
Run Code Online (Sandbox Code Playgroud)

所以第一个版本(使用null-coalescing运算符)产生了更多的IL.

但有两点需要注意:

  1. 这个IL是使用MoveDevelop的东西 - 如果你在Visual Studio中编译它,它很可能是一个不同的故事.也许它在微软的编译器中进行了优化.即使它们与它们相同,另一个人的编译器也可以轻松优化它.仅仅因为某些编译器存在某些东西,并不意味着你会期望它来自每个人的编译器.
  2. CLR使用JIT.即使在编译时没有对其进行优化,它也可能在运行时进行了优化.事实上,这很可能就是为什么编译不关心这样的微优化.