在某些方法中,编译在固定块之后省略代码

Chr*_*tle 6 c# il visual-studio-2013

我们在其中一个项目中的类中有以下方法:

private unsafe void SomeMethod()
{
    // Beginning of the method omitted for brevity

    var nv = new Vector4[x];

    fixed (Vector4* vp = nv)
    {
        fixed (float* tp = /* Source float ptr */)
        {
            fixed (double* ap = /* Source double ptr */)
            {
                for (var i = atlArray.Length - 1; i >= 0; --i)
                {
                    vp[((i + 1) << 3) - 2] = new Vector4(tp[i], btt, 0.0f, 1.0f);
                    // Additional Vector4 construction omitted for brevity

                    nttp[i] = new Vector2(tp[i], this.ttvp);
                    nts[i] = string.Format(ap[i], /* etc. */);
                }
            }
        }
    }

    this.ts = nts;
    this.ttp = nttp;
    this.V = nv; // <- This is a property setter
}
Run Code Online (Sandbox Code Playgroud)

我不得不对此进行模糊处理,但希望它仍然清晰,可以了解正在发生的事情.

在我们的一个开发人员的机器上,在调试版本中,C#编译器删除了fixed块关闭后发生的三个分配.如果我们尝试在这些行上放置断点,断点将在应用程序启动时跳转到方法的结束括号.在fixed块和方法结束之间出现的代码也会在其他方法中被删除,但令人费解的是,并非在所有方法中都被删除.

经过一些实验,我们发现为受影响的项目启用优化会导致丢失代码.但是,这种解决方法无法进行单元测试 - 缺少代码,更改受影响项目及其测试项目的优化也无济于事.我们还发现,在最内层fixed语句中移动三个赋值是有效的 - 在检查IL时,它变得清晰.

在受影响的计算机上构建的调试DLL中(关闭优化),ap从堆栈弹出后直接出现返回操作:

IL_03a1:  nop
IL_03a2:  ldc.i4.0
IL_03a3:  conv.u
IL_03a4:  stloc.s    ap
IL_03a6:  ret
Run Code Online (Sandbox Code Playgroud)

这解释了为什么在stloc指令工作之前移动三个作业.在我的机器上构建的调试DLL中,返回操作发生在三个赋值之后的预期位置:

IL_03a5:  nop
IL_03a6:  ldc.i4.0
IL_03a7:  conv.u
IL_03a8:  stloc.s    ap
IL_03aa:  nop
IL_03ab:  ldc.i4.0
IL_03ac:  conv.u
IL_03ad:  stloc.s    tp
IL_03af:  nop
IL_03b0:  ldc.i4.0
IL_03b1:  conv.u
IL_03b2:  stloc.s    vp
IL_03b4:  ldarg.0
IL_03b5:  ldloc.s    nts
IL_03b7:  stfld      string[] N.B.E.B::ts
IL_03bc:  ldarg.0
IL_03bd:  ldloc.s    nttp
IL_03bf:  stfld      valuetype [SharpDX]SharpDX.Vector2[] N.B.E.B::ttp
IL_03c4:  ldarg.0
IL_03c5:  ldloc.s    nv
IL_03c7:  call       instance void N.B.E.B::set_V(valuetype [SharpDX]SharpDX.Vector4[])
IL_03cc:  nop
IL_03cd:  ret
Run Code Online (Sandbox Code Playgroud)

到目前为止,我们未能制作出一个SSCCE--这似乎只在非常具体的情况下才会出现,而且只在我们的一个项目中出现.我们检查过两台机器上都使用了相同版本的Visual Studio,.NET框架,C#编译器和MSBuild.我们检查了其他潜在的差异,如操作系统版本和更新.两台机器上的情况似乎相同(它们与笔记本电脑的型号相同).坦率地说,我们有点困惑.任何帮助将非常感激.

Chr*_*tle 0

我的同事(其机器受到影响的开发人员)发现构建的诊断输出存在差异 - 这是 C# 编译器。我们认为 MSBuild 在预期位置(c:\Program Files (x86)\MSBuild\12.0\Bin)使用 csc.exe,但奇怪的是,它实际上是在C:\Users\[user ]\AppData\Local\Microsoft\VisualStudio\12.0\Extensions,它有一个完全不同的版本。我们不知道该编译器可执行文件是如何出现的,也不知道 MSBuild 如何引用它,但是一旦将其删除,MSBuild 就会恢复使用其主 Bin 目录中的 csc.exe 版本,并且代码将被删除现在已正确构建。