为什么会出现在一座建于VS 2010 VS应用程序的行为差异VS 2012? [英] Why is there a difference in behaviour of an application built in VS 2010 v.s. VS 2012?

查看:266
本文介绍了为什么会出现在一座建于VS 2010 VS应用程序的行为差异VS 2012?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我被检查是否对我们的构建机器上安装.NET 4.5通过改变VS 2010生成的输出IL形象。

因为我知道的foreach的行为已经改变了.NET 4.5,以避免因问题<一href="http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx">Access要修改封,我选择了表现出行为的简单应用程序。

 类节目
    {
        私有静态无效的主要(字串[] args)
        {
            VAR内容=新的名单,其中,Func键&LT; INT&GT;&GT;();
            变种S =新的StringBuilder();

            INT []值=新INT [] {4,5,6};

            的foreach(中值int值)
            {
                contents.Add(()=&GT;值);
            }

            为(变种K = 0; K&LT; contents.Count; k ++)
                s.Append(内容[k]的());

            Console.WriteLine(多个);
        }
 

VS 2010的输出:666

VS 2012的输出:456

我创建在VS 2010中一个控制台应用程序,并使用相同的code在VS 2012(有针对性.NET 4)控制台应用程序。

不过,无论是控制台应用程序展示基础上,他们建立了与IDE不同的行为。在构建输出,我查了一下,这两个有近类似的建设的论点。所以,我不知道如何结束可执行表现不同的行为? .NET 4.5是一个in-place升级,所以编译器为集成开发环境必须是相同的。

注:我也有看一个相关的问题:<一href="http://stackoverflow.com/questions/13327224/different-linq-answer-in-vs-2010-and-vs-2012">Different LINQ答案在VS 2010和VS 2012 但它并没有回答我为什么可执行文件的行为不同的问题。

修改1: 由于 mletterle 提到的,我也尝试建立使用命令行的VS 2010的VS输出窗口中的code 2010命令提示符。由此产生的输出表现,就好像它是建立在VS 2012。

编辑2:

我张贴在输出窗口输出present:

VS 2010: 建设开始二〇一二年十二月二十〇日下午11时04分56秒。

  

CoreClean:创建目录的obj \ 86 \调试\。   GenerateTargetFrameworkMonikerAttribute:跳过目标   GenerateTargetFrameworkMonikerAttribute,因为所有输出文件   向上最新与相对于输入文件。 CoreCompile:
  C:\ WINDOWS \ Microsoft.NET \框架\ v4.0.30319 \ CSC.EXE / noconfig   / nowarn:1701,1702包括/ nostdlib + /平台:86 / errorreport:提示/警告:4   /定义:DEBUG,TRACE / errorendlocation / preferreduilang:EN-US   / highentropyva- /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ Microsoft.CSharp.dll   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ mscorlib.dll中   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Core.dll的   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Data.DataSetExtensions.dll   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Data.dll中   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.dll中   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ system.xml.dll的   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Xml.Linq.dll   /调试+ /调试:全/ filealign:512 / optimize-   /out:obj\x86\Debug\TestConsoleApp.exe /目标:EXE / utf8output   Program.cs的属性\ AssemblyInfo.cs中   C:\用户\ 105044960 \应用程序数据\本地\ Temp.NETFramework,版本= v4.0.AssemblyAttributes.cs   _CopyAppConfigFile:跳过目标_Cop​​yAppConfigFile,因为所有输出文件都是最新相对于输入文件。   CopyFilesToOutputDirectory:从复制文件   OBJ \ 86 \调试\ TestConsoleApp.exe到斌\调试\ TestConsoleApp.exe。   TestConsoleApp - > C:\用户\ 105044960 \文档\ Visual Studio的   2010 \项目\ TestConsoleApp \ TestConsoleApp \斌\调试\ TestConsoleApp.exe   从OBJ \ 86 \调试\ TestConsoleApp.pdb复制文件   斌\调试\ TestConsoleApp.pdb。

VS 2012:

  

1> CoreClean:1>删除文件C:\用户\ 105044960 \文档\ Visual   工作室   11 \项目\ TestConsoleApp \ TestConsoleApp \斌\调试\ TestConsoleApp.exe。   1>删除文件C:\用户\ 105044960 \文档\ Visual Studio中   11 \项目\ TestConsoleApp \ TestConsoleApp \斌\调试\ TestConsoleApp.pdb。   1>删除文件C:\用户\ 105044960 \文档\ Visual Studio中   11\Projects\TestConsoleApp\TestConsoleApp\obj\Debug\TestConsoleApp.csprojResolveAssemblyReference.cache".   1>删除文件C:\用户\ 105044960 \文档\ Visual Studio中   11 \项目\ TestConsoleApp \ TestConsoleApp \ OBJ \调试\ TestConsoleApp.exe。   1>删除文件C:\用户\ 105044960 \文档\ Visual Studio中   11 \项目\ TestConsoleApp \ TestConsoleApp \ OBJ \调试\ TestConsoleApp.pdb。   1> GenerateTargetFrameworkMonikerAttribute:1>跳过目标   GenerateTargetFrameworkMonikerAttribute,因为所有输出文件   向上最新与相对于输入文件。 1> CoreCompile:1>   C:\ WINDOWS \ Microsoft.NET \框架\ v4.0.30319 \ CSC.EXE / noconfig   / nowarn:1701,1702,2008包括/ nostdlib + /平台:值为anycpu / errorreport:提示   /警告:4 /定义:DEBUG,TRACE / errorendlocation / preferreduilang:EN-US   / highentropyva- /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ Microsoft.CSharp.dll   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ mscorlib.dll中   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Core.dll的   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Data.DataSetExtensions.dll   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Data.dll中   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.dll中   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ system.xml.dll的   /参考:C:\ Program Files文件(x86)的\参考   大会\微软\ Framework.NETFramework \ V4.0 \ System.Xml.Linq.dll   /调试+ /调试:全/ filealign:512 / optimize-   /out:obj\Debug\TestConsoleApp.exe /目标:EXE / utf8output的Program.cs   属性\ AssemblyInfo.cs中   C:\用户\ 105044960 \应用程序数据\本地\ Temp.NETFramework,版本= v4.0.AssemblyAttributes.cs   1> CopyFilesToOutputDirectory:1>复制的文件   OBJ \调试\ TestConsoleApp.exe到斌\调试\ TestConsoleApp.exe。 1>   TestConsoleApp - > C:\用户\ 105044960 \文档\ Visual Studio的   11 \项目\ TestConsoleApp \ TestConsoleApp \斌\调试\ TestConsoleApp.exe   1>从OBJ \调试\ TestConsoleApp.pdb复制文件   斌\调试\ TestConsoleApp.pdb。

解决方案

Visual Studio中使用了的过程中的编译器,因此它知道C#的版本它的使用。

正如您所指出的,在命令行csc.exe的,而另一方面,无论使用C#版本它是由编译,所以在您的情况这将是C#5.0。因为它是一个就地升级(在安装目录而言),它有可能打破code,它在整个循环依赖于的foreach 绑定是相同的(奇,但有可能)。


  

注:错误的问题老答案:OP的知道这一点,并在命令行测试它

您链接到该博客文章已经回答了你的问题。我认为这个问题是有关这个

这改变了编译器,所以这样的:

 的foreach(中值int值)
{
    // ...
}
 

用于生成内容大致如下code的内容:

  {
    int值;
    对(/ *迭代* /)
    {
        值= / *从枚举获得* /;
        // ...
    }
}
 

而新的C#编译器现在生成的变量移动到循环内的等效的:

 的(/ *迭代* /)
{
    int值= / *从枚举获得* /;
    // ...
}
 

这使得有很大的区别,因为在 // ... 将捕获新的值封绑定而不是共享相同的绑定,用来在循环外部声明。在每个周期中,

美中不足的是,如果你希望你的code正确地为老年人和新的编译器,您必须声明自己的变量的foreach 循环中:

 的foreach(中值int值)
{
    INT为newValue =价值;
    // ...
}
 


目前的C#4.0规范在Visual Studio 2010中说:

  

(...)一个foreach形式的声明

 的foreach(V V IN x)的嵌入语句
 

     

然后扩展为:

  {
  E E =((C)(X))的GetEnumerator()。
  尝试 {
      V伏;
      而(e.MoveNext()){
          V =(V)(T)e.Current;
          嵌入语句
      }
  }
  最后 {
      ... //处置Ë
  }
}
 

在C#5.0规范在Visual Studio 2012说:

  

(...)一个foreach形式的声明

 的foreach(V V IN x)的嵌入语句
 

     

然后扩展为:

  {
  E E =((C)(X))的GetEnumerator()。
  尝试 {
      而(e.MoveNext()){
          V V =(V)(T)e.Current;
          嵌入语句
      }
  }
  最后 {
      ... //处置Ë
  }
}
 

I was checking whether installing .NET 4.5 on our build machines changes the output IL image generated by VS 2010.

Since I know the behaviour of foreach has changed in .NET 4.5 to avoid issues due to Access to Modified closure, I chose a simple application that exhibited the behaviour.

  class Program
    {
        private static void Main(string[] args)
        {
            var contents = new List<Func<int>>();
            var s = new StringBuilder();

            int[] values = new int[] { 4, 5, 6 };

            foreach (int value in values)
            {
                contents.Add(() => value);
            }

            for (var k = 0; k < contents.Count; k++)
                s.Append(contents[k]());

            Console.WriteLine(s);
        }

VS 2010 output: 666

VS 2012 output: 456

I created a console application in VS 2010 and a console application with the same code in VS 2012 (both targeted .NET 4).

However, both the console applications exhibited different behaviours based on the IDE they were built with. In the build output, I checked that both had nearly similar build arguments. So I was wondering how the end executable exhibited different behaviour? .NET 4.5 is an in-place upgrade, so the compiler for both IDEs must be the same.

NOTE: I did have a look at a related question: Different LINQ Answer in VS 2010 and VS 2012 but it did not answer my question on why the executable behaviour differed.

EDIT 1: As mletterle mentioned, I did try building the code using the commandline in the output window of VS 2010 in a VS 2010 command prompt. The resulting output behaved as if it was built with VS 2012.

EDIT 2:

I am posting the output present in Output Window:

VS 2010: Build started 12/20/2012 11:04:56 PM.

CoreClean: Creating directory "obj\x86\Debug\". GenerateTargetFrameworkMonikerAttribute: Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files. CoreCompile:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe /noconfig /nowarn:1701,1702 /nostdlib+ /platform:x86 /errorreport:prompt /warn:4 /define:DEBUG;TRACE /errorendlocation /preferreduilang:en-US /highentropyva- /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\Microsoft.CSharp.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\mscorlib.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Core.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Data.DataSetExtensions.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Data.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Xml.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Xml.Linq.dll" /debug+ /debug:full /filealign:512 /optimize- /out:obj\x86\Debug\TestConsoleApp.exe /target:exe /utf8output Program.cs Properties\AssemblyInfo.cs "C:\Users\105044960\AppData\Local\Temp.NETFramework,Version=v4.0.AssemblyAttributes.cs" _CopyAppConfigFile: Skipping target "_CopyAppConfigFile" because all output files are up-to-date with respect to the input files. CopyFilesToOutputDirectory: Copying file from "obj\x86\Debug\TestConsoleApp.exe" to "bin\Debug\TestConsoleApp.exe". TestConsoleApp -> C:\Users\105044960\Documents\Visual Studio 2010\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.exe Copying file from "obj\x86\Debug\TestConsoleApp.pdb" to "bin\Debug\TestConsoleApp.pdb".

VS 2012:

1>CoreClean: 1> Deleting file "c:\users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.exe". 1> Deleting file "c:\users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.pdb". 1> Deleting file "c:\users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\obj\Debug\TestConsoleApp.csprojResolveAssemblyReference.cache". 1> Deleting file "c:\users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\obj\Debug\TestConsoleApp.exe". 1> Deleting file "c:\users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\obj\Debug\TestConsoleApp.pdb". 1>GenerateTargetFrameworkMonikerAttribute: 1>Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files. 1>CoreCompile: 1> C:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe /noconfig /nowarn:1701,1702,2008 /nostdlib+ /platform:AnyCPU /errorreport:prompt /warn:4 /define:DEBUG;TRACE /errorendlocation /preferreduilang:en-US /highentropyva- /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\Microsoft.CSharp.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\mscorlib.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Core.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Data.DataSetExtensions.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Data.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Xml.dll" /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Xml.Linq.dll" /debug+ /debug:full /filealign:512 /optimize- /out:obj\Debug\TestConsoleApp.exe /target:exe /utf8output Program.cs Properties\AssemblyInfo.cs "C:\Users\105044960\AppData\Local\Temp.NETFramework,Version=v4.0.AssemblyAttributes.cs" 1>CopyFilesToOutputDirectory: 1> Copying file from "obj\Debug\TestConsoleApp.exe" to "bin\Debug\TestConsoleApp.exe". 1> TestConsoleApp -> C:\Users\105044960\Documents\Visual Studio 11\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.exe 1> Copying file from "obj\Debug\TestConsoleApp.pdb" to "bin\Debug\TestConsoleApp.pdb".

解决方案

Visual Studio uses an in-process compiler, so it knows which version of C# it's using.

As you noted, csc.exe from the command line, on the other hand, uses whatever C# version it's made to compile, so in your case it'll be C# 5.0. Since it's an in-place upgrade (in terms of installation directory), it might break code that relied on the foreach binding being the same across the whole loop (odd, but possible).


NOTE: Old answer for the wrong question: the OP knows this and was testing it from the command line.

The blog post you link to already answers your question. I think this question is related to this one.

It's the compiler that changed, so this:

foreach (int value in values)
{
    // ...
}

used to generate something along the following code:

{
    int value;
    for (/* iteration */)
    {
        value = /* get from enumerator */;
        // ...
    }
}

while the new C# compiler now generates the equivalent of moving the variable to inside the loop:

for (/* iteration */)
{
    int value = /* get from enumerator */;
    // ...
}

This makes a great difference, since closures within the // ... will capture a new value binding in each cycle, instead of sharing the same value binding that used to be declared outside the loop.

The catch is, if you want your code to work correctly for both older and newer compilers, you must declare your own variable inside the foreach loop:

foreach (int value in values)
{
    int newValue = value;
    // ...
}


The current C# 4.0 specification in Visual Studio 2010 says:

(...) A foreach statement of the form

foreach (V v in x) embedded-statement

is then expanded to:

{
  E e = ((C)(x)).GetEnumerator();
  try {
      V v;
      while (e.MoveNext()) {
          v = (V)(T)e.Current;
          embedded-statement
      }
  }
  finally {
      … // Dispose e
  }
}

The C# 5.0 specification in Visual Studio 2012 says:

(...) A foreach statement of the form

foreach (V v in x) embedded-statement

is then expanded to:

{
  E e = ((C)(x)).GetEnumerator();
  try {
      while (e.MoveNext()) {
          V v = (V)(T)e.Current;
          embedded-statement
      }
  }
  finally {
      … // Dispose e
  }
}

这篇关于为什么会出现在一座建于VS 2010 VS应用程序的行为差异VS 2012?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆