尽管我们可以将新类型作为 NuGet 包来提供,但我们不能以这种方式在现有类型上提供新的 API 。因此从一般意义上讲,BCL 中的创新需要交付新版本的.NET Standard 。
在.NET Standard 2.0 之前,这并不是什么大问题,因为我们仅对现有的 API 进行了标准化 。但是在.NET Standard 2.1 中,我们对全新的 API 进行了标准化,因此我们遇到了很多麻烦 。
这种摩擦从何而来?
.NET Standard 是所有.NET 实现都必须支持的 API 集,因此它有一个编辑准则,即所有 API 必须由.NET Standard 审查委员会审查 。该委员会由.NET 平台实现者和.NET 社区的代表组成,目标是仅标准化我们可以在所有当前和将来的.NET 平台中真正实现的 API 。这些检查是必要的,因为.NET 堆栈的实现方式不同,约束条件也不同 。
我们预测到了这种摩擦,这就是为什么我们之前提到.NET Standard 只会标准化至少在一个.NET 实现中提供 API 的原因 。一开始这似乎挺合理,但随后,你就意识到.NET Standard 不能频繁发布新版本 。因此,如果某个特性错过了某个特定版本,则可能需要等上几年才能发布,甚至可能需要更长时间才能等到这个版本的.NET Standard 得到广泛支持 。
对某些特性来说,我们感到机会成本太高了,因此我们采取了非常规的行动来标准化尚未交付的 API(例如IAsyncEnumerable<T>) 。但是,对所有特性都这么做,实在是太昂贵了,这就是为什么许多特性仍然错过了.NET Standard 2.1 的原因(例如新的硬件内部函数) 。
但是,如果只有一个代码库呢?如果这个代码库需要支持现在让.NET 实现分裂的所有选项,例如同时支持即时(JIT)编译和提前(AOT)编译,又会怎么样?
从一开始,我们就将所有这些选项都纳入了特性设计,而不是事后才考虑 。在这种情况下,标准化的 API 集在构造上就是通用的 API 集 。一个特性被实现后,由于代码库是共享的,因此这个特性立刻就能被所有人使用 。
问题 2:.NET Standard 需要解码环将 API 集与对应的实现分离,不仅仅是减缓了 API 的可用性,这也意味着我们需要将.NET Standard 版本映射到它们的实现上 。随着时间的推移,我需要向越来越多的人解释这种关系,于是发现这种看似简单的想法其实非常复杂 。我们尽了最大的努力来简化它,但毕竟这是固有的复杂性,因为 API 集和实现是分开独立提供的 。
我们统一了 .NET 平台,在它们下面又增加了一个合成平台,代表了通用的 API 集 。这幅受 XKCD 启发的漫画就画得很明白:

文章插图
.NET 5 要做的就是真正在框架中合并一些部分,从而解决这个问题:.NET 5 提供了一个统一的实现,所有部分都在相同的基础上构建,并因此获得相同的 API 形状和版本号 。
问题 3:.NET Standard 公开了特定平台 API在设计.NET Standard 时,我们必须做出务实的妥协,以免对库生态系统造成过大的破坏 。换句话说,我们必须包括一些只适用于Windows 的API(例如文件系统ACL、注册表、WMI 等) 。展望未来,我们将避免在 net5.0、net6.0和以后的版本中添加特定于平台的 API 。但我们无法预测未来,例如,借助 Blazor WebAssembly,我们最近添加了一个新环境,可以在其中运行.NET,可浏览器的沙箱中不支持某些跨平台 API(例如线程或进程控制) 。
很多人抱怨说,这类 API 就像“地雷”一样——代码编译没有错误,因此似乎可以移植到任何平台,但是在没有针对给定 API 实现的平台上运行时就会出现运行时错误 。
从.NET 5 开始,我们将默认随附带有 SDK 的分析器和代码修复程序,其中包括平台兼容性分析器,该分析器可检测到你准备运行的平台上不支持哪些API,并报告相应的意外使用情况 。此特性替代了 Microsoft.DotNet.Analyzers.Compatibility NuGet 包 。
首先,让我们看一下 Windows 专属的 API 。
处理特定于 Windows 的 API创建以 net5.0 为目标的项目时,可以引用 Microsoft.Win32.Registry 包 。但当你开始使用它时,会收到以下警告:
private static string GetLoggingDirectory(){using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"SoftwareFabrikam")){if (key?.GetValue("LoggingDirectoryPath") is string configuredPath)return configuredPath;}string exePath = Process.GetCurrentProcess().MainModule.FileName;string folder = Path.GetDirectoryName(exePath);return Path.Combine(folder, "Logging");}CA1416: 'RegistryKey.OpenSubKey(string)' is supported on 'windows'CA1416: 'Registry.CurrentUser' is supported on 'windows'CA1416: 'RegistryKey.GetValue(string?)' is supported on 'windows'
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .net core IIS部署教程
- 为什么中国火器到清朝就停止发展了 清朝为何不发展火器
- 基于.NET Core+Bootstrap的快速后台开发框架
- 基于.NET Core的Orchard Core框架出来了
- 自媒体|趣头条宣布停止自媒体平台:6月28日后账户余额清零
- .Net在Windows上使用Jenkins做CI/CD
- ppt背景音乐怎么中途暂停后继续播放?ppt音乐怎么中途停止?
- .NET CORE HttpClient使用
- C语言标准库的7类函数
- 巧克力|这类常见的零食立即停止食用!或导致中毒
