MSBuild v14 在极少数情况下会编译语义不正确的程序集

MSBuild v14 compiles a semantically incorrect assembly under some rare circumstances

构建环境更新后,我们的一项冒烟测试在 TeamCity 中出现故障。调查结果表明,从相同的源代码,

什么时候出现

重现它的示例代码

static void Main(string[] args)
{
    var customerId = Guid.NewGuid();

    // Produces buggy code when compiled with MSBuild v14
    TestMethodWithParams(args: customerId, whatever: "foo");

    //All the calls below result correct behavior, regardless of the version of MSBuild, order and naming of parameters
    TestMethodWithParams("foo", customerId);
    TestMethodWithParams(whatever: "foo", args: customerId);

    TestMethodWithParams(args: new object[] { customerId }, whatever: "foo");
    TestMethodWithParams("foo", new object[] { customerId });
    TestMethodWithParams(whatever: "foo", args: new object[] {customerId});
}

private static void TestMethodWithParams(string whatever, params object[] args)
{
    Console.WriteLine("args: '{0}'", args);
}

到底发生了什么

不正确的版本只是吞掉了单个参数,正在传递null。反编译代码显示差异:

正确的二进制格式:

Guid guid = Guid.NewGuid();
Program.TestMethodWithParams("foo", new object[]
{
    guid
});

二进制文件不正确:

Guid guid = Guid.NewGuid();
object obj;
Program.TestMethodWithParams("foo", new object[]
{
    obj // <- this is and will always be null
});

如何修复

当我们将单个参数包装到一个对象数组中时,问题就消失了。另一种选择是不使用命名参数,and/or 确保参数在调用和签名中出现的顺序相同。

但是:主要问题是我们无法恢复到较旧的 MSBuild (...),并且检查整个代码库(并检查我们 NuGet 包中的每个二进制文件)也不是一个简单有效的解决方案。此外,这种错误可能会在以后的任何时候意外地重新引入代码库。因此,最好的解决方案可能是以某种方式修复 MSBuild。

有没有人经历过这样的事情?可能是 MSBuild 中的错误?想法?

正如我在 GitHub 问题中提到的那样,我相信这是最初报告为 #4197 并在 Roslyn 1.1 中修复的错误。

感谢您提供的所有信息和建议。您分享了帮助我们追踪此问题的详细信息。原来安装 "Microsoft Build Tools 2015 with Update 2" 解决了我们的问题。

再次感谢大家。 /大卫