Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 当用于自赋值时,编译器是否优化空合并运算符?_.net_C# 4.0 - Fatal编程技术网

.net 当用于自赋值时,编译器是否优化空合并运算符?

.net 当用于自赋值时,编译器是否优化空合并运算符?,.net,c#-4.0,.net,C# 4.0,这两个代码块在功能上是相同的 if (myObj == null) { myObj = new MyObj(); } 及 但是,在myObj不为null的情况下,使用null合并运算符的方法会执行不必要的赋值。但后来我想也许编译器会优化这些自赋值。有人知道编译器是否会注意到正在发生的事情,并将底部代码段转换为顶部代码段吗?刚刚在LinqPad中尝试过: void Main() { MyObj myObj = null; myObj = myObj ?? new MyOb

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

if (myObj == null)
{
    myObj = new MyObj();
}


但是,在myObj不为null的情况下,使用null合并运算符的方法会执行不必要的赋值。但后来我想也许编译器会优化这些自赋值。有人知道编译器是否会注意到正在发生的事情,并将底部代码段转换为顶部代码段吗?

刚刚在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     

因此,无论
myObj
是否为空,赋值(
stloc.0
在IL_000C)似乎都已完成。。。但也许JIT稍后会对此进行优化。

为了比较,我尝试编译了这两个版本

object myObj = null;
myObj = myObj ?? new object();

Main
方法的内部。(我正在Mono2.6.7上使用MonoDevelop 2.4)

如果代码按预期进行了优化,我们应该会看到生成类似的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 
}
第二个版本:

.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 
}
因此,第一个版本(使用空合并操作符)生成了稍微多一些IL

但有两件事需要注意:

  • 这个IL就是我使用MoveDevelop得到的——如果你在Visual Studio中编译它,它很可能是另一个故事。也许它是在微软的编译器中优化的。即使它们也是一样的,另一个人的编译器也可以轻松地对此进行优化。仅仅因为某些东西适用于某些编译器,并不意味着你会从每个人的编译器中得到它
  • CLR使用JIT。即使这不是在编译时优化的,也可能是在运行时优化的。事实上,这很可能就是编译不太关心这种微观优化的原因

  • 这是出于好奇,我意识到这是可以忽略的不同。请避免“过早优化”的评论:)为什么不检查使用?如果myObj是一个属性,那么可能的重复不一定相同。@Marcelo-有趣的是,如果它是一个属性,它可能会不同。你能再解释一下吗?既然
    myObj
    为空,那么作业当然就完成了。这就是空合并操作符的全部目的@肯,在这种情况下它是空的,但编译器没有考虑到这一点。。。该值可能来自其他地方,它将为
    myObj=myObj???生成相同的IL??新MyObj().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 
    }