C# 在VS2010中或通过MsBuild命令行编译解决方案时,生成的代码不同

C# 在VS2010中或通过MsBuild命令行编译解决方案时,生成的代码不同,c#,visual-studio-2010,msbuild,C#,Visual Studio 2010,Msbuild,我有以下C#代码: 如果我在VS2010中编译解决方案,将生成以下代码(使用IlSpy反编译): 如果通过MsBuild命令行编译解决方案,将生成以下代码: using (List<X>.Enumerator enumerator = this.m_collection.GetEnumerator()) { while (enumerator.MoveNext()) { X x = enumerator.Current; m_actio

我有以下C#代码:

如果我在VS2010中编译解决方案,将生成以下代码(使用IlSpy反编译):

如果通过MsBuild命令行编译解决方案,将生成以下代码:

using (List<X>.Enumerator enumerator = this.m_collection.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        X x = enumerator.Current;
        m_actionCollection.Add(() =>
        {
            x.DoSomething();
        });         
    }
}
使用(List.Enumerator Enumerator=this.m_collection.GetEnumerator())
{
while(枚举数.MoveNext())
{
X=枚举数。当前值;
m_actionCollection.Add(()=>
{
x、 DoSomething();
});         
}
}
项目文件包含

<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
v4.0
MsBuild命令行如下所示:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MsBuild.exe Solution.sln/property:Configuration=Debug/property:Platform=x86/maxcpucount/nologo/toolsversion:4.0

所以我假设编译器是一样的,但它不是


要通过MsBuild命令行和VS2010构建完全相同的环境,必须执行/检查哪些操作?

我怀疑您看到了C#5编译器(通过MsBuild调用)和C#4编译器(在VS2010中)之间的差异。我对msbuild使用C#5编译器感到有点惊讶,但它似乎是

如何捕获
foreach
迭代变量的规则在C#4和C#5之间发生变化。在C#5中,
foreach
循环的每次迭代都有效地捕获不同的变量。在C#4中,所有迭代都捕获相同的变量

这意味着您的原始代码在C#4中有效地被破坏了,但在C#5中却很好。在C#4中,如果您随后执行
m#u actionCollection
中的所有操作,它将对
m#u collection
的最后一项调用
DoSomething()
很多次(
m#u collection.Count
次)。在C#5中,它将对
m#u集合的每个项目调用
DoSomething
一次

不清楚ILSpy语言的有效反编译版本是什么也无济于事:(

必须执行哪些操作/检查哪些操作才能通过MsBuild命令行和VS 2010创建完全相同的环境

我强烈建议,最简单的方法是改用VS2012或VS2013

您可以通过查看msbuild日志,查看
CoreCompile
步骤使用的是哪个版本的
csc.exe
来检查这一点。一旦知道使用的是哪个编译器二进制文件,您就可以从命令行运行编译器,然后根据需要进行修补

当我使用
/toolsversion:4.0
运行
msbuild
时,它使用
c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe
,它本身报告:

Microsoft(R)Visual C#编译器版本4.0.30319.33440 适用于Microsoft(R).NET Framework 4.5

这似乎是一个C#5编译器,尽管它的名字是这样的。我怀疑这是由于.NET4.5是一个就地升级

检查您真正使用的编译器的最简单方法是尝试包含
async
方法。例如,下面是一个完整的类:

class Test { static async void Foo() {} }

如果编译时出现警告CS1998(“此异步方法缺少等待运算符…”),则它使用的是C#5编译器。较旧的编译器将出现错误(可能是“无效标记'void'…”)

是的,我知道我的代码已损坏,但如果没有此警告,我不会注意到使用了不同的编译器版本:-)。如何强制MsBuild使用与VS2010相同的编译器版本?感谢您的详细解释。尽管版本号混乱,但VS 2010使用的.NET 4.0(C#4.0)的csc.exe在哪里可以找到?@Harry13:恐怕我不能告诉你,部分原因是我自己没有安装它。它甚至可能无法以独立的形式提供,但我建议您在计算机上查找所有出现的
csc.exe
。同样,如果可能的话,我鼓励您升级:)它是相同的可执行文件。通过比较VS和命令行MsBuild的详细MsBuild输出发现。在命令行中,参数似乎与该问题没有什么不同。在命令行生成的MsBuild日志中,似乎怀疑以下消息:使用程序集“Microsoft.build.Tasks.v4.0,版本=4.0.0.0,区域性=中性,PublicKeyToken=b03f5f7f11d50a3a”中的“Csc”任务。这只发生在MsBuild中,而不发生在VS2010@Harry13:真奇怪。不幸的是,如果没有安装VS2010,我将很难复制和进一步挖掘:(
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
class Test { static async void Foo() {} }