C#编译器版本和语言版本的区别

27

曾经我认为框架版本和C#版本是相同的,所以一旦在计算机上安装了下一个框架版本,就应该使用它。

然后我发现框架与C#版本没有直接关联,并且在同一台计算机上可以共存多个C#编译器,因此编译器和C#版本可能应该相同。

现在我明白编译器版本和C#版本并不相同......


Visual Studio命令提示符(2010):C:\>csc

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


VS开发人员命令提示符(2013):C:\>csc

Microsoft (R) Visual C# 编译器版本 12.0.30110.0
适用于 C# 5


enter image description here

我们可以看出:
- VS 2010使用编译器版本4.0来构建C#4(??我只能猜测,因为没有明确提到);
- VS 2013使用编译器版本12.0来构建C# 5(明确提到)

根据使用不同语言版本进行编译可能会给用户带来不同的结果

问题

  • 如何找出VS用于构建我的具体项目的C#版本(不是编译器版本,而是语言版本)?

  • C# 编译器版本语言版本之间是否有严格、清晰、透明的关联?

  • 当我在不同版本的Visual Studio之间迁移时,我可以指示Visual Studio(针对迁移问题)为我的具体解决方案使用不同的编译器版本吗?


  • 也许不是回答问题,但供参考:C#的正确版本号是什么? - default
    1
    @Thorsten Dittmar:不是的。同一个框架可以使用不同的C#版本(编译器)。 - serhio
    1
    @Default: 相关问题将.NET Framework版本与C#版本联系起来。我询问编译器和语言之间的同样联系,不关心框架。 - serhio
    1
    @ThorstenDittmar请查看问题中的链接。 - serhio
    1
    这是VS2013中重要的msbuild重新组织的一部分。输入“where csc.exe”以查看发生了什么。使用Visual Studio命令提示符等命令的目的是让微软来担心正确性问题。 - Hans Passant
    显示剩余3条评论
    5个回答

    25

    由于没有人给出足够好的答案,我现在来试一试。

    首先,C#现在已经由Microsoft发布其版本历史(显然来自MVP帖子),

    https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-version-history

    所以你可以轻松地看到每个新版本中添加了哪些新特性。

    其次,我们将讨论编译器发布,这最初是.NET Framework的一部分。

    下面我列出了一些里程碑(可能不是100%正确,有些版本可能被跳过),

    • csc.exe 1.0(?)用于.NET Framework 1.0(实现了C# 1.0)。
    • csc.exe 2.0(Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.8745)用于.NET Framework 2.0(实现了C# 2.0,以及1.0以保持兼容性)。
    • csc.exe 3.5(Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.8763)用于.NET Framework 3.5(实现了C# 3.0和早期版本)。
    • csc.exe 4.0(?)用于.NET Framework 4.0(实现了C# 4.0和早期版本)。
    • csc.exe 4.x(例如 Microsoft (R) Visual C# Compiler version 4.7.2053.0)用于.NET Framework 4.5及以上版本(实现了C# 5.0和早期版本)。请注意,版本号因您计算机上的.NET Framework而异(从4.x到12.x,从4.5.0到4.7.1)。

    微软将旧的csc.exe(因为它们是本机可执行文件)作废,并改用基于Roslyn的编译器代替(尽管仍然使用csc.exe)。与此同时,C#编译器不再是.NET Framework的一部分,而是Visual Studio的一部分。

    同时,C#编译器、语言版本和.NET Framework已完全解耦,因此您可以轻松地使用多目标。

    • Roslyn csc.exe 1.x (?) 实现了 C# 6.0 及更早版本,随VS2015一起发布。
    • Roslyn csc.exe 2.x(类似于 Microsoft (R) Visual C# Compiler 版本 2.4.0.62122 (ab56a4a6))实现了 C# 7.x 及更早版本,随VS2017一起发布。

    好了,足够背景知识了。回答你的问题。

    Q1:如何找出 VS 使用哪个 C# 版本(不是编译器版本)来构建我的具体项目?

    答:您可以从项目设置中轻松看出所使用的语言版本。

    高级设置

    如果您没有选择明确的版本,它可以自动使用csc.exe编译项目支持的最新版本。

    请注意,@Servy 在 @DaniloCataldo 的答案下评论了langversion开关的更多详细信息。该开关具有其设计目标和限制。因此,即使您强制Roslyn 2.x编译器基于C# 4.0编译您的项目,编译结果也会与C# 4.0编译器不同。

    Q2:C#编译器和语言版本之间是否存在严格、清晰和透明的联系?

    答案:请参考我上面描述的背景,我认为已经回答了这部分内容。存在一个严格、清晰和透明的链接。

    Q3:如果从一个Visual Studio版本迁移时遇到的问题,我可以指示Visual Studio使用不同的编译器版本来解决吗?

    答案:Visual Studio发布(如VS2019)会固定于一个MSBuild版本(16.x),因此会有一个专用版本的C#编译器。因此,通常情况下Q3是重复的Q1,因为您只能更改语言版本。

    有一堆NuGet包可以覆盖项目使用的C#编译器,例如https://www.nuget.org/packages/Microsoft.Net.Compilers.Toolset。然而,微软表示“将其用作在旧版MSBuild安装上提供更新的编译器的长期解决方案明确不受支持”,因此您真的不应该探索那条路。


    好久不见了,感谢您的详细回答。您在第3个问题的答案中写道重复Q1,但我认为它没有回答这个问题。我仍然不明白如何控制编译器版本?例如,我想使用较新的VS版本来编译旧版本的编译器,这是可能的吗?如果可以,该怎么做呢?谢谢。 - MaorB
    @MaorB 只有 C++ 项目从头开始设计支持该场景,而 C# 项目不支持。 - Lex Li
    好的,谢谢。所以如果我想使用与我最初创建应用程序时使用的相同编译器版本进行编译,我需要使用最初使用的相同的VS版本,是吗? - MaorB
    1
    @MaorB 对的。你最好使用旧版的VS,以保持你的环境足够稳定。新版本的VS绑定了新版本的MSBuild和C#编译器,所以从那里回去是不可能的。 - Lex Li

    3

    补充之前的答案。 需要注意的是,虽然C#语言和C#编译器与.Net框架是分开的,但它们仍然依赖于它。

    例如,C# 5具有await/async语言特性,但您不能在.Net 4中使用它,至少不是没有额外的操作和nuget包。

    另一方面,您仍然可以使用C# 6的nameof或null传播功能与.Net 4.0,因为它们纯粹由编译器实现。


    3
    过去,Visual Studio 2005版本只能支持一个.Net版本和内置的C#编译器。如果您想使用更新版本的VS,则需要切换到新版本的Visual Studio。现在,Visual Studio可以针对多个.Net版本进行开发,甚至可以将新的C#编译器与旧版的.Net框架相结合(在.Net 2.0中使用lambda表达式或扩展方法)。简单来说,C#编译器版本与C#语言版本相关
    您可以在项目文件中查看编译器版本(以xml格式打开),并在Project元素中找到ToolsVersion属性。
    在我的特定项目中,ToolsVersion="4.0",而我的目标项目是.Net 2.0。这意味着我可以在旧框架中使用新的语言构造,在VS2005中是不可能的。

    我不认为更改工具版本会更改编译器版本,我刚测试过了,将工具版本设置为较低的数字并没有改变 测试程序 的输出,在旧版编译器下应该展示不同的行为。 - Scott Chamberlain
    谢谢您的回答。是否有任何参考资料可以说明编译器和语言版本之间的具体关系?比如说,如果我想使用C#5,我应该针对哪个编译器版本进行目标设置? - serhio
    1
    @Scott Chamberlain 看起来VS2010会自动将此属性升级到4.0:https://dev59.com/wk3Sa4cB1Zd3GeqPwZi6 - Aik

    0

    判断编译器支持的语言版本的一种方法是使用

    csc -langversion:?

    命令,然后会得到响应。

    Supported language versions:
    default
    1
    2
    3
    4
    5
    6
    7.0
    7.1
    7.2
    7.3
    8.0
    9.0 (default)
    latestmajor
    preview
    latest
    

    -1

    为了告诉Visual Studio使用哪个语言版本,有一个编译器选项叫做/langversion。
    你可以在这里找到更多信息。
    它也可以通过编程方式设置,如此处所述。
    编译器可以编译不同版本的语言,语言版本与框架版本没有直接关系,但通常要使用语言特性,需要至少一个最低的框架版本才能工作。
    就在几分钟前,我在VS 2015中编译了一个使用C# 6.0字符串插值的dll。

    var version = 4;
    var output = $"{version}";
    

    并且以框架4.0为目标。 它可以编译并正常工作。 这篇文章解释了版本纠缠问题,但仅适用于旧的c#版本。


    langversion开关并不改变实际的语言版本(与其名称所暗示的相反)。 它只会导致某些功能的使用在编译时出现错误。 除了添加新功能之外,C#版本之间有很多变化,因此使用langversion开关将3.0设置为在C#7编译器上编译的代码将与在C#3.0编译器上编译的代码有所不同 - Servy

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接