【发布时间】:2021-09-08 13:12:48
【问题描述】:
在 Visual Studio 2019 高级构建设置中,C# 8 似乎不适用于 .NET Framework 项目,仅(如下图所示)适用于 .NET Core 3.0 项目:
C# 8 是否支持 .NET Framework?
【问题讨论】:
标签: c# .net visual-studio .net-standard c#-8.0
在 Visual Studio 2019 高级构建设置中,C# 8 似乎不适用于 .NET Framework 项目,仅(如下图所示)适用于 .NET Core 3.0 项目:
C# 8 是否支持 .NET Framework?
【问题讨论】:
标签: c# .net visual-studio .net-standard c#-8.0
是的,C# 8 可以在 Visual Studio 2019 中与 .NET Framework 和其他早于 .NET Core 3.0/.NET Standard 2.1 的目标一起使用(如果您@ 987654321@).
唯一需要的是在 csproj 文件中将语言版本设置为8.0。您也可以在 Directory.Build.props 中执行此操作,以将其应用于解决方案中的所有项目。请阅读下文,了解如何在 Visual Studio 2019 版本 16.3 及更高版本中执行此操作。
大多数(但不是全部)功能都适用于任何目标框架。
以下功能仅是语法更改;无论框架如何,它们都可以工作:
这些需要 .NET Framework 中没有的新类型。它们只能与“polyfill”NuGet 包或代码文件一起使用:
Default interface members 不会在 .NET Framework 下编译并且永远不会工作,因为它们需要在 CLR 中进行运行时更改。 .NET CLR 现在已冻结,因为 .NET Core 现在是前进的方向。
如需更多关于哪些功能有效、哪些无效以及可能的 polyfill 的信息,请参阅 Stuart Lang 的文章C# 8.0 and .NET Standard 2.0 - Doing Unsupported Things。
以下 C# 项目以 .NET Framework 4.8 为目标并使用 C# 8 可空引用类型在 Visual Studio 16.2.0 中编译。我通过选择 .NET 标准类库模板创建它,然后将其编辑为以 .NET Framework 为目标:
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
.cs:
namespace ClassLibrary1
{
public class Class1
{
public string? NullableString { get; set; }
}
}
然后我尝试了一个 .NET Framework 4.5.2 WinForms 项目,使用旧的 .csproj 格式,并添加了相同的可为空的引用类型属性。我将 Visual Studio 高级构建设置对话框(在 16.3 中禁用)中的语言类型更改为 latest 并保存了项目。当然,在这一点上它没有建立。我在文本编辑器中打开项目文件,并在构建配置PropertyGroup 中将latest 更改为preview:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<LangVersion>preview</LangVersion>
然后我通过将<Nullable>enable</Nullable> 添加到主PropertyGroup 来启用对可空引用类型的支持:
<PropertyGroup>
<Nullable>enable</Nullable>
我重新加载了项目,它构建了。
Visual Studio 2019 版本 16.3 的 RTM 版本,C# 8.0 的发布版本发生了重大变化:语言选择下拉菜单已被禁用:
Microsoft 的 rationale 是:
向前看,...每个框架的每个版本都将有一个 支持和默认版本,我们不会支持任意 版本。为了反映支持的这种变化,这个提交永久 禁用语言版本组合框并添加文档链接 解释变化。
打开的文档是C# language versioning。这仅将 C# 8.0 列为 .NET Core 3.x 的默认语言。它还确认每个框架的每个版本都将有一个受支持的默认版本,并且不再依赖该语言的框架无关性。
仍然可以通过编辑 .csproj 文件将 .NET Framework 项目的语言版本强制为 8。
第一次编写此答案时,C# 8 处于预览阶段,涉及大量侦探工作。我将这些信息留给后代。如果您不需要了解所有血腥细节,请随意跳过。
C# 语言在历史上一直是 mostly framework neutral - 即能够编译旧版本的框架 - 尽管某些功能需要新类型或 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 框架 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 package 来使用它们。 Visual Studio 明白这一点,一切都很好。
不过,Mads 也写道:
因此,仅在实现 .NET Standard 2.1 的平台上支持使用 C# 8.0。
...如果属实,将排除使用带有 any 版本的 .NET Framework 的 C# 8,甚至在最近才鼓励我们使用的 .NET Standard 2.0 库中库代码的基线目标。您甚至无法将它与 3.0 之前的 .NET Core 版本一起使用,因为它们也只支持 .NET Standard 2.0。
调查开始了! -
Jon Skeet 有一个使用 C# 8 ready to go 的 Noda-Time 的 alpha 版本,它仅针对 .NET Standard 2.0。他显然期望 C# 8/.NET Standard 2.0 支持 .NET 家族中的所有框架。 (另请参阅 Jon 的博文 "First steps with nullable reference types")。
Microsoft 员工一直在讨论 C# 8 可空引用类型 on GitHub 的 Visual Studio UI,并表示他们打算支持旧版 csproj(.NET Core SDK 之前的格式 csproj)。这是一个非常强烈的迹象,表明 C# 8 将与 .NET Framework 一起使用。 [我怀疑他们会回溯这件事,因为 Visual Studio 2019 语言版本下拉菜单已被禁用并且 .NET 已与 C# 7.3 绑定]
在著名的博文之后不久,GitHub thread 讨论了跨平台支持。出现的一个重要点是.NET Standard 2.1 will include a marker that denotes that default implementations of interfaces is supported - 该功能需要对.NET Framework 永远不可用的CLR 更改。这是重要的一点,来自 Microsoft .NET 团队的项目经理 Immo Landwerth:
编译器(例如 C#)应使用此字段的存在来决定是否允许默认接口实现。如果该字段存在,则预计运行时能够加载并执行生成的代码。
IIRC,绝对不会出现在 .NET Framework 上的唯一功能是 DIM(默认接口方法),因为它需要运行时更改。其他功能由类的形状驱动,这些类可能永远不会添加到 .NET Framework,但可以通过您自己的代码或 NuGet(范围、索引、异步迭代器、异步处置)进行 polyfill。
Victor Derks 评论说:“设计更复杂的可空用例所需的 new nullable attributes 仅在 .NET Core 3.0 和 .NET Standard 2.1 附带的 System.Runtime.dll 中可用...... [并且] 不兼容使用 .NET Framework 4.8"
但是,Immo Landwerth commented 在文章 Try out Nullable Reference Types 下指出“我们的绝大多数 API 不需要任何自定义属性,因为类型要么是完全通用的,要么不为空”。
Ben Hall 在 GitHub 上提出了问题Availability of nullable attributes outside of Core 3.0,以下来自 Microsoft 员工的 cmets 值得关注:
仅 .net core 3.0 和 .net standard 2.1 将完全支持 C# 8。 如果您手动编辑项目文件以将 C# 8 与 .net core 2.1 一起使用, 你在不受支持的领域。一些 C# 8 特性将发生在 运行良好,某些 C# 8 特性运行不太好(例如,差 性能),一些 C# 8 特性将与额外的 hack 一起使用,还有一些 C# 8 功能根本不起作用。解释起来很复杂。我们不 主动阻止它,以便可以浏览它的专家用户可以 这样做。我不推荐使用这种不受支持的混搭 广泛。
(简·科塔斯)
像你这样愿意理解并围绕他们工作的人—— 可以免费使用 C# 8。关键是,并非所有语言功能都可以使用 下层目标。
(伊莫兰德韦斯)
Microsoft 不正式支持 C# 8/.NET Framework 组合。他们说,它仅供专家使用。
【讨论】:
csproj 中的<Nullable>enable</Nullable> 指定时不支持可为空的引用类型。使用 #nullable enable 指令时它似乎有效。另请参阅:github.com/dotnet/project-system/issues/5551
根据this blog entry,该语言确实与框架相关:
这意味着使用这些功能所需的类型在 .NET Framework 4.8 上不可用。同样,默认接口成员实现依赖于新的运行时增强,我们也不会在 .NET Runtime 4.8 中实现。
因此,仅在实现 .NET Standard 2.1 的平台上支持使用 C# 8.0。十多年来,为了保持运行时稳定,我们一直无法在其中实现新的语言特性。凭借现代运行时的并行和开源性质,我们认为我们可以负责任地再次发展它们,并在考虑到这一点的情况下进行语言设计。 Scott 在他的 .NET Core 3.0 和 .NET Framework 4.8 更新中解释说,.NET Framework 未来的创新将更少,而是专注于稳定性和可靠性。鉴于此,我们认为它错过某些语言功能总比无人获得它们要好。
【讨论】:
C# 8.0(及更高版本)仅在 .NET Core 3.x 及更高版本上受支持 版本。许多最新功能需要库和运行时 .NET Core 3.x 中引入的功能: C# language versioning
【讨论】: