Gan*_* R. 19 .net visual-studio-2010 visual-studio-2012
我正在检查在我们的构建机器上安装.NET 4.5是否会更改VS 2010生成的输出IL映像.
因为我知道在.NET 4.5中foreach的行为已经改变以避免由于访问修改闭包引起的问题,所以我选择了一个展示该行为的简单应用程序.
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);
}
Run Code Online (Sandbox Code Playgroud)
VS 2010输出:666
VS 2012输出:456
我在VS 2010中创建了一个控制台应用程序,在VS 2012中创建了一个具有相同代码的控制台应用程序(都是针对.NET 4).
但是,两个控制台应用程序都基于它们构建的IDE表现出不同的行为.在构建输出中,我检查了两者都有几乎相似的构建参数.所以我想知道最终可执行文件如何表现出不同的行为?.NET 4.5是就地升级,因此两个IDE的编译器必须相同.
注意:我确实看过一个相关的问题:VS 2010和VS 2012中的不同LINQ答案,但它没有回答我关于可执行行为不同的问题.
编辑1: 正如mletterle所提到的,我确实尝试在VS 2010命令提示符中使用VS 2010的输出窗口中的命令行构建代码.结果输出表现得好像是使用VS 2012构建的.
编辑2:
我发布输出窗口中的输出:
VS 2010: Build 12/20/2012 11:04:56 PM
CoreClean:创建目录"obj\x86\Debug \".GenerateTargetFrameworkMonikerAttribute:跳过目标"GenerateTargetFrameworkMonikerAttribute",因为所有输出文件都是相对于输入文件的最新文件.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)\参考程序集\ Microsoft\Framework.NETFramework\v4.0\System.Data.dll"/ reference:"C:\ Program Files(x86)\ Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.dll"/参考:"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:跳过目标"_CopyAppConfigFile"因为所有输出文件都是相对于输入文件的最新文件.CopyFilesToOutputDirectory:将文件从"obj\x86\Debug\TestConsoleApp.exe"复制到"bin\Debug\TestConsoleApp.exe".TestConsoleApp - > C:\ Users\105044960\Documents\Visual Studio 2010\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.exe将文件从"obj\x86\Debug\TestConsoleApp.pdb"复制到"bin\Debug\TestConsoleApp" .PDB".
VS 2012:
1> CoreClean:1>删除文件"c:\ users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.exe".1>删除文件"c:\ users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.pdb".1>删除文件"c:\ users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\obj\Debug\TestConsoleApp.csprojResolveAssemblyReference.cache".1>删除文件"c:\ users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\_ obj\Debug\TestConsoleApp.exe".1>删除文件"c:\ users\105044960\documents\visual studio 11\Projects\TestConsoleApp\TestConsoleApp\_ obj\Debug\TestConsoleApp.pdb".1> GenerateTargetFrameworkMonikerAttribute:1>跳过目标"GenerateTargetFrameworkMonikerAttribute",因为所有输出文件都是相对于输入文件的最新文件.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:\程序文件(x86)\参考程序集\ 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.NETFr amework\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>将文件从"obj\Debug\TestConsoleApp.exe"复制到"bin\Debug\TestConsoleApp.exe".1> TestConsoleApp - > C:\ Users\105044960\Documents\Visual Studio 11\Projects\TestConsoleApp\TestConsoleApp\bin\Debug\TestConsoleApp.exe 1>将文件从"obj\Debug\TestConsoleApp.pdb"复制到"bin\Debug"\TestConsoleApp.pdb".
注意:我删除了原始回复的大部分内容.它回答了错误的问题.随后会有更好的回应.
啊,现在我看到你在问什么:"安装.NET 4.5后,Visual Studio 2010如何知道编译到C#4而不是C#5,甚至Visual Studio 2010和Visual Studio 2012使用相同的csc.exe并通过相同的选择呢?"
@mletterle但是.NET 4.5是对.NET 4的升级版.所以我的机器上只有.NET 4.唯一的可能是IDE隐藏了我看不到的.NET 4编译器的隐藏副本.
我不确定你在哪里听到这个或为什么你这么认为..NET 4.5不是就地升级.它是该工具的不同版本.会有分歧.这是其中之一.
更新1:
看起来我们使用了不同的"就地"升级定义.我对"就地"的使用是"升级,版本之间应该没有明显的区别." 您链接的文章中给出的定义以不同的方式使用它:在其使用中"就地"是"使用相同的CLR,但添加新库".
由于C#5与C#4不同,因此在我熟悉的用法中,该更改并非"到位".
因此,差异不是您要定位的CLR,而是您正在使用的语言版本 - CLR是"就地"升级(均为4.0 CLR),但语言不是(VS2010中的C#4) ,VS2012中的C#5.)
更新2:
在.csproj文件(实际上是由Visual Studio管理的msbuild文件)中,有一个属性指定目标框架.默认情况下,使用Visual Studio 2012制作的项目具有此功能:
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
Run Code Online (Sandbox Code Playgroud)
Visual Studio 2010中针对版本4的项目如下所示:
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
Run Code Online (Sandbox Code Playgroud)
这告诉Visual Studio在构建一个或另一个目标框架时设置环境.虽然看起来直接从命令提示符调用csc.exe,但实际上并非如此:msbuild项目实际上是正在处理的内容,它发生在"Visual Studio"的自定义进程环境中.
我只能假设发生了什么的具体细节,但是在升级之后,将"TargetFrameworkVersion"属性设置为v4.0会在编译面向v4.0的项目期间将环境返回到v4.0.另一方面,通过从命令行调用csc.exe而没有msbuild设置的环境,它使用其版本的"默认值"(现在默认为C#5),即使你使用了新的C#5行为'使用VS 2010命令提示符.但是,当您通过MSBuild调用构建时,它知道如何在构建期间返回到原始C#4环境(因为MSBuild也是.NET工具链的一部分).
Visual Studio 使用进程内编译器,因此它知道它正在使用哪个版本的 C#。
\n\n正如您所指出的,另一方面,命令行中的 csc.exe 使用它编译的任何 C# 版本,因此在您的情况下它将是 C# 5.0。由于它是就地升级(就安装目录而言),因此它可能会破坏依赖于foreach整个循环中相同的绑定的代码(奇怪,但可能)。
\n\n\n注意:错误问题的旧答案:OP知道这一点并且正在从命令行测试它。
\n
您链接到的博客文章已经回答了您的问题。我认为这个问题与这个有关。
\n\n是编译器改变了,所以:
\n\nforeach (int value in values)\n{\n // ...\n}\nRun Code Online (Sandbox Code Playgroud)\n\n用于沿着以下代码生成一些内容:
\n\n{\n int value;\n for (/* iteration */)\n {\n value = /* get from enumerator */;\n // ...\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n而新的 C# 编译器现在生成将变量移动到循环内部的等效项:
\n\nfor (/* iteration */)\n{\n int value = /* get from enumerator */;\n // ...\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这有很大的不同,因为 中的闭包// ...将在每个循环中捕获一个新的value绑定,而不是共享value过去在循环外声明的相同绑定。
问题是,如果您希望代码在旧版和新版编译器中都能正常工作,则必须在循环内声明自己的变量foreach:
foreach (int value in values)\n{\n int newValue = value;\n // ...\n}\nRun Code Online (Sandbox Code Playgroud)\n\nVisual Studio 2010 中当前的 C# 4.0 规范规定:
\n\n\n\n\n(...) 形式的 foreach 语句
\n\nRun Code Online (Sandbox Code Playgroud)\n\nforeach (V v in x) embedded-statement\n然后扩展为:
\n\nRun Code Online (Sandbox Code Playgroud)\n{\n E e = ((C)(x)).GetEnumerator();\n try {\n V v;\n while (e.MoveNext()) {\n v = (V)(T)e.Current;\n embedded-statement\n }\n }\n finally {\n \xe2\x80\xa6 // Dispose e\n }\n}\n
Visual Studio 2012 中的 C# 5.0 规范表示:
\n\n\n\n(...) 形式的 foreach 语句
\n\nRun Code Online (Sandbox Code Playgroud)\n\nforeach (V v in x) embedded-statement\n然后扩展为:
\n\nRun Code Online (Sandbox Code Playgroud)\n{\n E e = ((C)(x)).GetEnumerator();\n try {\n while (e.MoveNext()) {\n V v = (V)(T)e.Current;\n embedded-statement\n }\n }\n finally {\n \xe2\x80\xa6 // Dispose e\n }\n}\n
| 归档时间: |
|
| 查看次数: |
2355 次 |
| 最近记录: |