C#8是否支持.NET Framework?

Jam*_*urt 52 .net c# visual-studio .net-standard c#-8.0

在Visual Studio 2019 Advanced Build设置中,C#8似乎不适用于.NET Framework项目,而仅适用于.NET Core 3.0项目(如下图所示):

在此处输入图片说明

C#8是否支持.NET Framework?

Ste*_*edy 88

是的,C#8可以与.NET Framework和Visual Studio 2019中的.NET Core 3.0 / .NET Standard 2.1之前的其他目标一起使用(如果安装了Nuget包,则可以与Visual Studio的旧版本一起使用)。

语言版本必须8.0在csproj文件中设置为。

无论针对哪个框架,大多数(但不是全部)功能都可用。


起作用的功能

以下功能仅是语法更改;无论框架如何,它们都可以工作:

可以使用的功能

这些要求使用.NET Framework中没有的新类型。它们只能与“ polyfill” Nuget软件包或代码文件结合使用:

默认界面成员-不起作用

默认接口成员将无法在.NET下编译,并且将永远无法工作,因为它们需要在CLR中更改运行时。.NET CLR现在冻结了,因为.NET Core现在是前进的方向。

有关什么能起作用,什么不能起作用以及可能的填充的更多信息,请参见Stuart Lang的文章C#8.0和.NET Standard 2.0-做不受支持的事情


以下针对.NET 4.8的C#项目和使用C#8可为空的引用类型在Visual Studio 16.2.0中进行编译。我通过选择.NET标准类库模板,然后将其编辑为目标.NET来创建它:

.csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net48</TargetFrameworks>
    <LangVersion>8.0</LangVersion>
    <Nullable>enable</Nullable>
  </PropertyGroup>
</Project>
Run Code Online (Sandbox Code Playgroud)

.cs:

namespace ClassLibrary1
{
    public class Class1
    {
        public string? NullableString { get; set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,我尝试使用旧.csproj格式的.NET 4.5.2 WinForms项目,并添加了相同的可为空的引用类型属性。我将Visual Studio高级构建设置对话框(在16.3中禁用)中的语言类型更改为latest并保存了项目。当然,这一点不会建立。我在文本编辑器中打开了项目文件,并在构建配置中将其更改latest为:previewPropertyGroup

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
   <LangVersion>preview</LangVersion>
Run Code Online (Sandbox Code Playgroud)

然后,我通过添加<Nullable>enable</Nullable>到main来启用对可为空的引用类型的支持PropertyGroup

<PropertyGroup>
   <Nullable>enable</Nullable>
Run Code Online (Sandbox Code Playgroud)

我重新加载了项目,然后构建。


血腥细节

首次编写此答案时,C#8处于预览阶段,涉及许多侦探工作。我将这些信息留在这里供后人参考。如果您不需要了解所有血腥细节,请随时跳过它。

C#语言历来大部分都是框架无关的,即能够编译框架的旧版本,尽管某些功能需要新的类型或CLR支持。

大多数C#爱好者将阅读Mads Torgersen 的博客条目Building C#8.0,该博客文章解释了C#8的某些功能具有平台依赖性:

异步流,索引器和范围都依赖于.NET Standard 2.1 .... NET Core 3.0以及Xamarin,Unity和Mono将全部实现.NET Standard 2.1的新框架类型,但是.NET Framework 4.8将实现不。这意味着使用这些功能所需的类型在.NET Framework 4.8中不可用。

这看起来有点像C#7中引入的Value Tuples。该功能需要新的类型- ValueTuple结构-在4.7以下的NET Framework版本或早于2.0的.NET Standard中不可用。但是,C#7仍然可以在.NET的旧版本中使用,既可以不使用值元组,也可以通过安装System.ValueTuple Nuget软件包与它们一起使用。Visual Studio理解了这一点,并且一切都很好。

但是,Mads也写道:

因此,仅在实现.NET Standard 2.1的平台上支持使用C#8.0。

...如果为真,则将排除在任何版本的.NET Framework中使用C#8,甚至在.NET Standard 2.0库中(实际上直到最近才鼓励我们将其用作库代码的基准目标)的可能性。您甚至无法在3.0之前的.NET Core版本中使用它,因为它们也仅支持.NET Standard 2.0。

调查正在进行中!--

  • 乔恩·斯凯特(Jon Skeet)使用C#8 准备了Noda-Time的Alpha版本,该版本仅面向.NET Standard 2.0。他显然希望C#8 / .NET Standard 2.0支持.NET系列中的所有框架。(另请参见Jon的博客文章“具有可空引用类型的第一步”)。

  • 微软员工一直在GitHub上讨论Visual Studio UI for C#8可为空的引用类型,并且据称他们打算支持旧版csproj(.NET Core SDK之前的格式csproj)。这非常有力地表明C#8将可与.NET Framework一起使用。[我怀疑由于Visual Studio 2019语言版本下拉列表已被禁用并且.NET已与C#7.3绑定,因此他们现在将对此进行回溯]

  • 著名博客文章发表后不久,GitHub线程讨论了跨平台支持。出现的重要一点是.NET Standard 2.1将包含一个标记,该标记表示支持接口的默认实现 -该功能需要CLR更改,而该更改永远不会对.NET Framework可用。这是Microsoft .NET团队程序经理Immo Landwerth的重要内容:

    期望编译器(例如C#)使用此字段的存在来决定是否允许默认接口实现。如果存在该字段,则预期运行时能够加载和执行结果代码。

  • 所有这些都指出“ C#8.0仅在实现.NET Standard 2.1的平台上受支持”是一个过分的简化,而C#8将支持.NET Framework,但是由于存在太多不确定性,我在GitHub上问,HaloFour回答:

    IIRC,绝对不会出现在.NET Framework上的唯一功能是DIM(默认接口方法),因为它需要更改运行时。其他功能由可能从未添加到.NET Framework中的类的形状驱动,但可以通过您自己的代码或NuGet(范围,索引,异步迭代器,异步处理)进行多填充。

  • Victor Derks评论说:“ 设计更复杂的可空使用案例所需的新可空属性仅在与.NET Core 3.0和.NET Standard 2.1一起提供的System.Runtime.dll中可用... [并且]与.NET Framework不兼容4.8“

  • 但是,Immo Landwerth 在“ 尝试可空引用类型 ”一文中评论说:“我们的大多数API都不需要任何自定义属性,因为类型是完全通用的或非空的”

  • Ben Hall在GitHub 的Core 3.0之外提出了可为空的属性的可用性问题,并请注意Microsoft员工的以下评论:

仅在.net core 3.0和.net standard 2.1上完全支持C#8。如果您手动编辑项目文件以将C#8与.net core 2.1一起使用,则您处于不受支持的地区。一些C#8功能会碰巧运行良好,一些C#8功能将不能很好地工作(例如,性能较差),某些C#8功能会受到额外的黑客攻击,而某些C#8功能将根本无法工作。解释很复杂。我们不会主动阻止它,因此可以浏览它的专家用户可以这样做。我不建议广泛使用这种不受支持的混合匹配。

(Jan Kotas)

像您这样愿意理解并在其中解决问题的人可以自由使用C#8。要点是,并非所有语言功能都可以在下层目标上使用。

(Immo Landwerth)


Visual Studio 2019

Visual Studio 2019版本16.3的RTM版本已发生重大变化-C#8.0的启动版本:语言选择下拉列表已被禁用:

在此处输入图片说明

微软对此的理由是:

展望未来,...每个框架的每个版本都会有一个受支持的默认版本,我们将不支持任意版本。为了反映对支持的更改,此提交将永久禁用语言版本组合框,并向说明更改的文档添加链接。

打开的文档为C#语言版本控制。这列出了C#8.0作为.NET Core 3.x的默认语言。它还确认了每个框架的每个版本都将具有单个受支持的默认版本,并且不再依赖于该语言的框架不可知论。

对于.NET Framework项目,仍然可以通过编辑.csproj文件将语言版本强制为8。


买者自负

Microsoft尚未正式支持C#8 / .NET Framework组合。他们说,这仅适用于专家。

  • 这应该可以消除由于我们可以(如果我们尝试)使用标准 2.1 之外的一些 C# 8 功能而产生的任何混乱 - https://github.com/dotnet/corefx/issues/40039 (3认同)
  • @BenHall 我已经从您的问题中添加了一些要点 - 非常感谢您提出问题并在这里发帖。如果答案有任何不正确之处,请随时编辑。 (3认同)
  • 当通过“csproj”中的“&lt;Nullable&gt;enable&lt;/Nullable&gt;”指定时,Visual Studio 2019 IntelliSense 不支持可空引用类型。使用“#nullable enable”指令时它似乎有效。另请参阅:https://github.com/dotnet/project-system/issues/5551 (3认同)
  • @odalet 我不会对 C# 8 的目标和使用不需要 polyfill 的基本功能(已经这样做)感到不安,也可能使用 polyfill(不需要它们)。然而,我能给出的最好建议是:如果有疑问,就不要这样做,至少在你的工作依赖于此的情况下不要这样做。 (3认同)
  • 设计更复杂的可为空用例所需的新可为空属性 (https://docs.microsoft.com/en-us/dotnet/csharp/nullable-attributes) 仅在 .NET 附带的 System.Runtime.dll 中可用核心 3.0 和 .NET 标准 2.1。这使得可为 null \ C# 8.0 与 .NET Framework 4.8 不兼容 (2认同)
  • @VictorDerks 这是很好的信息,谢谢。我在答案中直接引用了你的话。如果答案有任何不正确之处,请随时编辑。 (2认同)
  • 可空属性可以在您自己的项目中使用(编译器将尊重它们),方法是将源代码包含在 https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System 中/Diagnostics/CodeAnalysis/NullableAttributes.cs 。在项目中设置编译器常量“INTERNAL_NULLABLE_ATTRIBUTES”可能是个好主意,这样属性上的可访问性修饰符将是“internal”;或手动更改修饰符。 (2认同)
  • 此外,[Reference Assembly Annotator](https://github.com/tunnelvisionlabs/ReferenceAssemblyAnnotator) 在 .NET Framework API 中已在 .NET Core 3.0 API 中添加的位置(例如“Dictionary”)向 .NET Framework API 添加了可空属性.TryGetValue`)。 (2认同)
  • 对于较旧的 .NET 版本,有一个纯源代码 [NuGet 包](https://github.com/manuelroemer/Nullable),它可以将可为空的属性添加到您的项目中。 (2认同)
  • @Bouke您使用的是旧式“.csproj”,还是 SDK 格式的 csproj?引用的问题是指旧式项目格式。 (2认同)
  • @ZevSpitz 是的;`&lt;Nullable&gt;` 是 `csproj` 中的一个配置元素(如我评论的答案所示)。 (2认同)
  • 因此,我想我们可以说在针对 .NET Standard 2.0 的项目中使用最新/8.0 版本的 C# 是“危险的”。它可以被一个 Netfx 应用程序使用,该应用程序不支持其依赖项的所有微妙之处,但没有什么可以阻止人们这样做。我对么? (2认同)
  • 是否有任何库可以为 .NET Framework 项目启用索引和范围? (2认同)
  • 一个非常有用的polyfill包是[PolySharp](https://www.nuget.org/packages/PolySharp/) (2认同)

use*_*290 30

根据此博客文章,该语言确实与该框架相关:

这意味着使用这些功能所需的类型在.NET Framework 4.8中不可用。同样,默认接口成员实现依赖于新的运行时增强功能,我们也不会在.NET Runtime 4.8中进行开发。

For this reason, using C# 8.0 is only supported on platforms that implement .NET Standard 2.1. The need to keep the runtime stable has prevented us from implementing new language features in it for more than a decade. With the side-by-side and open-source nature of the modern runtimes, we feel that we can responsibly evolve them again, and do language design with that in mind. Scott explained in his Update on .NET Core 3.0 and .NET Framework 4.8 that .NET Framework is going to see less innovation in the future, instead focusing on stability and reliability. Given that, we think it is better for it to miss out on some language features than for nobody to get them.

  • 斯蒂芬·肯尼迪的其他答案中有更多详细信息。事实上,当面向 .NET Framework 时,很容易使 C# 8.0 的大部分子集正常工作。但 C# 8.0 的某些部分需要对运行时进行更改,而 Microsoft 不会为“旧”.NET Framework 进行更改。他们似乎将语言版本和 .NET 版本更紧密地联系在一起。 (3认同)