乘风破浪,遇见最佳跨平台跨终端框架.Net Core/.Net生态 - 重新认识.Net、.Net Core、.Net Standard、.Net Framework、Mono的关系
什么是.Net
.NET是一个免费的跨平台开放源代码开发人员平台,用于生成多种类型的应用程序。.NET基于许多大规模应用在生产中使用的高性能运行时构建而来。
.NET是由微软维护的最新通用开发平台,其前身是.Net Core
。它可以在不同的平台上工作,并以一种使.NET快速、灵活和现代的方式进行了重新设计。这恰好是微软的主要贡献之一。开发人员现在可以用.NET构建安卓、iOS、Linux、Mac和Windows应用程序,而且都是开源的,使用MIT和Apache 2许可证,是.NET Foundation的项目。.NET支持三种语言:C#
、F#
、Visual Basic
。
.NET实现
.NET应用是针对一个或多个.NET实现开发的。.NET实现包括.NET Framework、.NET 5(和.NET Core)以及Mono。
.NET的每个实现都具有以下组件:
- 一个或多个运行时,例如.NET Framework CLR和.NET 5 CLR。
- 类库,例如.NET Framework基类库和.NET 5基类库。
- (可选)一个或多个应用程序框架,例如ASP.NET、Windows Forms和Windows Presentation Foundation(WPF)都包括在.NET Framework和.NET 5+中。
- 可包含开发工具。某些开发工具在多个实现之间共享。
Microsoft支持以下四种.NET实现:
- .NET 5(和.NET Core)及更高版本
- .NET Framework
- Mono
- UWP
.NET 6现在是主要的实现,是正在进行的开发的重点。.NET 6是基于单个代码基底进行构建的,该代码基底支持多个平台和许多工作负载,例如Windows桌面应用和跨平台控制台应用、云服务和网站。某些工作负载(例如.NET Web Assembly生成工具)作为可选安装提供。
.NET 5及更高版本
.NET 5+(以前称为.NET Core)是.NET的跨平台实现,专用于处理大规模的服务器和云工作负载。它还支持其他工作负载,包括桌面应用。可在Windows、macOS和Linux上运行。它可实现.NET Standard,因此面向.NET Standard的代码都可在.NET 5+上运行。ASP.NET Core、Windows窗体和Windows Presentation Foundation(WPF)都在.NET 5+上运行。
.NET 6是此.NET实现的最新版本。
.NET Framework
.Net Framework是自2002年起就已存在的原始.NET实现。4.5版以及更高版本实现.NET Standard,因此面向.NET Standard的代码都可在这些版本的.NET Framework上运行。它还包含一些特定于Windows的API,如通过Windows窗体和WPF进行Windows桌面开发的API。.NET Framework非常适合用于生成Windows桌面应用程序。
Mono
Mono是主要在需要小型运行时使用的.NET实现。它是在Android、macOS、iOS、tvOS和watchOS上驱动Xamarin应用程序的运行时,且主要针对小内存占用。Mono还支持使用Unity引擎生成的游戏。
它支持所有当前已发布的.NET Standard版本。
以前,Mono实现更大的.NET Framework API并模拟一些Unix上最常用的功能。有时使用它运行依赖Unix上的这些功能的.NET应用程序。
Mono通常与实时编译器一起使用,但它也提供在iOS之类的平台使用的完整静态编译器(预先编译)。
通用Windows平台(UWP)
https://docs.microsoft.com/zh-cn/windows/uwp/get-started/universal-application-platform-guide
UWP是用于为物联网(IoT)生成新式触控Windows应用程序和软件的.NET实现。它旨在统一可能想要以其为目标的不同类型的设备,包括电脑、平板电脑、电话,甚至Xbox。UWP提供许多服务,如集中式应用商店、执行环境(App Container)和一组Windows API(用于代替Win32(WinRT))。应用可采用C++、C#、Visual Basic和JavaScript编写。
.NET类库
类库是.NET的共享库概念。通过类库可将实用功能组件化为可供多个应用程序使用的模块。还可使用类库加载应用程序启动时不需要或未知的功能。类库通过.NET程序集文件格式进行描述。
有三种类型的类库可供使用:
- 平台特定的类库可访问给定平台(例如,Windows上的.NET Framework、Xamarin、iOS)中的所有API,但只有面向该平台的应用和库可使用该类库。
- 可移植类库可访问API的子集,并且可供面向多个平台的应用和库使用。
- .NET Standard类库将平台专用库概念和可移植库概念合并到一个模型中,以同时获取两方面的优势。
平台特定的类库
平台特定的类库绑定到单个.NET平台(例如,Windows上的.NET Framework),因此它可以在已知的执行环境上接收重要的依赖项。此类环境会公开一组已知API(.NET和OSAPI),维护并公开预期状态(例如,Windows注册表)。
创建平台特定的库的开发人员可充分利用基础平台。该库只会在给定平台上运行,因此不需要平台检查和其他形式的条件代码(针对多个平台取模单个源代码)。
平台特定的库一直是.NET Framework的主要类库类型。即使出现了其他.NET实现,平台特定的库也仍然是最主要的类库类型。
可移植类库
可移植库支持多个.NET实现。该库仍可在已知执行环境上接收依赖项,不过该环境是一种合成环境,由一组具体.NET实现的交集生成。公开的API和平台假设是平台特定的库可用的子集。
创建可移植库时,需选择平台配置。平台配置是需要支持的平台集(例如,.NET Framework 4.5+、Windows Phone 8.0+)。要支持的平台越多,可生成的API和平台假设就越少,公分母越小。这一特性可能最初会令人感到疑惑,因为人们常认为“越多越好”,但却发现更多的支持平台带来的可用API更少。
许多库开发人员已经从由一个源开发多个平台特定的库(使用条件编译指令)转向开发可移植库。有多种方法可在可移植库中访问平台特定的功能,其中“诱饵替换”是目前最广为接受的方法。
.NET Standard类库
https://docs.microsoft.com/zh-cn/dotnet/standard/net-standard
.NET Standard库是平台特定的库和可移植库概念的替代。.NET Core库可从基础平台公开所有功能(无合成平台或平台交集),就此而言,它是平台特定的库。该库可在所有支持平台上运行,就此而言,它是可移植库。
.NET Standard公开一组库协定。.NET实现必须完全支持每个协定,否则就全都不支持。因此,每个实现都支持一组.NET Standard协定。得出的必然结果是,.NET Standard类库在支持其协定依赖项的平台上受到支持。
.NET Standard不公开整个.NET Framework的功能(也不将此作为目标),但相比可移植类库,库公开的API更多。
以下实现支持.NET Standard库:
- .NET Core
- .NET Framework
- Mono
- 通用Windows平台(UWP)
Mono类库
Mono支持多种类库,包括上述三种类型的库。Mono通常被视为.NET Framework的跨平台实现。部分原因是,平台特定的.NET Framework库可在Mono运行时上运行,而无需修改或重新编译。创建可移植库之前,此特性就已存在,因此在.NET Framework和Mono之间启用二进制可移植性是显而易见的选择(虽然它只能单向运行)。
.NET Standard
.NET Standard是针对多个.NET实现推出的一套正式的.NET API规范。推出.NET Standard的背后动机是要提高.NET生态系统中的一致性。.NET 5及更高版本采用不同的方法来建立一致性,这种方法在大多数情况下都不需要.NET Standard。但如果要在.NET Framework和其他任何.NET实现(例如.NET Core)之间共享代码,则库必须面向.NET Standard 2.0。不会发布新版本的.NET Standard,但.NET 5、.NET 6以及所有将来的版本将继续支持.NET Standard 2.1及更早版本。
.NET Standard版本
已对.NET Standard进行版本控制。每个新版本都会添加更多API。当库是针对.NET Standard的某个版本生成时,它可以在任何实现该版本(或更高版本)的.NET Standard的.NET实现上运行。
面向更高版本的.NET Standard让库能够使用更多API,但这意味着它只能在较新版本的.NET上使用。面向较低版本会减少可用的API,但意味着库可以在更多位置运行。
.NET Standard 1.0提供37,118个可用API中的7,949个
.NET 实现 | 版本支持 |
---|---|
.NET 和.NET Core | 1.0、1.1、2.0、2.1、2.2、3.0、3.1、5.0、6.0 |
.NET Framework | 4.5、4.5.1、4.5.2、4.6、4.6.1、4.6.2、4.7、4.7.1、4.7.2、4.8 |
Mono | 4.6、5.4、6.4 |
Xamarin.iOS | 10.0、10.14、12.16 |
Xamarin.Mac | 3.0、3.8、5.16 |
Xamarin.Android | 7.0、8.0、10.0 |
通用 Windows 平台 | 8.0、8.1、10.0、10.0.16299,待定 |
Unity | 2018 年 1 月 |
.NET Standard 2.0提供37,118个可用API中的32,638个
.NET 实现 | 版本支持 |
---|---|
.NET 和.NET Core | 2.0、2.1、2.2、3.0、3.1、5.0、6.0 |
.NET Framework 1 | 4.6.1 2、4.6.2、4.7、4.7.1、4.7.2、4.8 |
Mono | 5.4、6.4 |
Xamarin.iOS | 10.14、12.16 |
Xamarin.Mac | 3.8、5.16 |
Xamarin.Android | 8.0、10.0 |
通用 Windows 平台 | 10.0.16299,待定 |
Unity | 2018 年 1 月 |
.NET Standard 2.1提供37,118个可用API中的37,118个
.NET 实现 | 版本支持 |
---|---|
.NET 和.NET Core | 3.0、3.1、5.0、6.0 |
.NET Framework 1 | N/A2 |
Mono | 6.4 |
Xamarin.iOS | 12.16 |
Xamarin.Mac | 5.16 |
Xamarin.Android | 10.0 |
通用 Windows 平台 | 待定 |
Unity | 2021.2 |
要定位哪个.NET Standard版本
建议定位.NET Standard 2.0,除非你需要支持早期版本。最常规用途的库应该不需要除.NET Standard 2.0之外的其他API。所有新式平台都支持.NET Standard 2.0,并且它是支持具有一个目标的多个平台的推荐方法。
如果需要定位.NET Standard 1.x,建议还定位.NET Standard 2.0。.NET Standard 1.x作为一组精细的NuGet包分发,它创建了一个大型的包依赖项关系图,并导致开发人员在构建时下载大量的包。
NET Standard版本控制规则
版本控制规则主要有两个:
- 累加性:.NET Standard版本在逻辑上形成同心圆。也就是说,较高的版本包含较低版本的所有API。版本之间没有重大更改。
- 不可变:一旦发布,.NET Standard版本就会冻结起来。
在.NET Standard 2.1版本之后,将不会有新版本。
.NET Framework兼容性模式
从.NET Standard 2.0开始,引入了.NET Framework兼容性模式。此兼容性模式允许.NET Standard项目引用.NET Framework库,就像其针对.NET Standard编译一样。引用.NET Framework库并不适用于所有项目,,例如使用Windows Presentation Foundation(WPF)API的库。
.NET Standard与.NET 5+
问题1:.NET Standard太慢
.NET Standard是在.NET平台在实现层面上没有融合的时候设计的。这使得编写需要在不同环境下工作的代码变得困难,因为不同的工作负载使用不同的.NET实现。
.NET Standard的目标是统一基础类库(BCL)的功能集,这样你就可以编写一个可以在任何地方运行的单一库。这对我们很有帮助:超过77%的前1000个软件包都支持.NET标准。如果我们看一下NuGet.org上所有在过去6个月内更新过的软件包,采用率为58%。
但是,单单对API集进行标准化就会产生一个税。每当我们增加新的API时,它都需要协调--这一直在发生。.NET开源社区(包括.NET团队)通过提供新的语言功能、可用性改进、新的跨领域功能(例如,支持新的数据格式或网络协议),不断在BCL中进行创新。
而我们可以作为NuGet包提供新的类型,但我们不能通过这种方式在现有类型上提供新的API。因此,从一般意义上讲,BCL的创新需要运送新版本的.NET标准。
直到.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标准被广泛支持。
我们觉得对于某些功能来说,机会损失太大,所以我们做了一些不自然的行为来规范那些还没有发货的API(比如)。对所有的功能都这样做简直是太昂贵了,这就是为什么相当多的功能仍然错过了.NET Standard 2.1的列车(比如新的硬件内在因素)。IAsyncEnumerable<T>
。
但是,如果有一个单一的代码库呢?如果这个代码库必须支持所有使.NET实现与众不同的方面,例如支持即时编译(JIT)和提前编译(AOT)呢?
我们不是在事后才做这些审查,而是从一开始就把所有这些方面作为功能设计的一部分。在这样一个世界里,标准化的API集在结构上就是通用API集。当一个功能被实现时,由于代码库是共享的,它已经可以为所有人所用。
问题2:.NET Standard需要一个解码器环
将API集与它的实现分开,不仅会减慢API的可用性。它还意味着我们需要将.NET Standard版本与它们的实现进行映射。作为一个不得不长期向许多人解释这个表格的人,我已经体会到这个看似简单的想法是多么复杂。我们已经尽力让它变得更简单,但最终,这只是固有的复杂性,因为API集和实现是独立运输的。
我们通过在它们下面添加另一个代表通用API集的合成平台,统一了.NET平台。在一个非常现实的意义上,这幅受XKCD启发的漫画是正确的。
如果不真正合并我们层图中的一些矩形,我们就无法解决这个问题,这就是.NET 5所做的:它提供了一个统一的实现,所有各方都建立在相同的基础上,从而获得相同的API形状和版本号。
问题3:.NET Standard暴露了特定平台的API
当我们设计.NET Standard时,我们不得不做出务实的让步,以避免过多地破坏库的生态系统。也就是说,我们不得不包括一些Windows专用的API(如文件系统ACL、注册表、WMI等)。今后,我们将避免在未来的版本中加入特定平台的API。然而,我们不可能预测未来。例如,对于Blazor WebAssembly,我们最近增加了一个新的环境,在这个环境中,.NET的运行和一些本来跨平台的API(如线程或进程控制)不能在浏览器的沙盒中得到支持。net5.0 net6.0
你们中的许多人都抱怨说,这些API感觉就像"地雷"--代码在编译时没有错误,因此看起来可以移植到任何平台上,但当在一个没有给定API实现的平台上运行时,你会得到运行时错误。
从.NET 5开始,我们在SDK中提供了分析器和代码修复器,这些都是默认的。这包括平台兼容性分析器,它可以检测出无意中使用了不被你打算运行的平台所支持的API的情况。这个功能取代了NuGet包 Microsoft.DotNet.Analyzers.Compatibility
。
让我们先来看看Windows特有的API。
处理与Windows特定的API
当你创建一个以net5.0为目标的项目时,你可以引用这个包。但当你开始使用它时,你会得到以下警告:Microsoft.Win32.Registry
private static string GetLoggingDirectory()
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Fabrikam"))
{
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'
对于如何处理这些警告,你有三个选择:
-
保护调用(Guard the call)。你可以通过使用
OperatingSystem.IsWindows()
在调用API之前检查你是否运行在Windows上。 -
将调用标记为Windows专用。在某些情况下,通过
[SupportedOSPlatform("windows")]
将调用成员标记为特定平台可能是合理的。 -
删除这段代码(Delete the code)。一般来说,这不是你想要的,因为这意味着当你的代码被Windows用户使用时,你会失去保真度,但对于存在跨平台替代方案的情况,你可能最好使用它而不是平台特定的API。例如,你可以使用一个XML配置文件,而不是使用注册表。
-
抑制警告(Suppress the warning)。你当然可以作弊,简单地抑制警告,可以通过或.NET来实现。 然而,在使用特定平台的API时,你应该更喜欢选项(1)和(2)。
为了保护调用,请使用System.OperatingSystem
类上的新静态方法,例如:
private static string GetLoggingDirectory()
{
if (OperatingSystem.IsWindows())
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Fabrikam"))
{
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");
}
要将你的代码标记为Windows专用,应用新的属性:SupportedOSPlatform
:
[SupportedOSPlatform("windows")]
private static string GetLoggingDirectory()
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Fabrikam"))
{
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");
}
在这两种情况下,使用注册表的警告都会消失。
关键的区别是,在第二个例子中,分析器现在会对调用网站发出警告,因为它现在被认为是一个Windows特定的API。换句话说,你把做平台检查的要求转发给你的调用者。GetLoggingDirectory()
该属性可以应用于成员、类型或汇编级别。这个属性也被BCL本身所使用。例如,程序集应用了这个属性,这就是分析器首先知道注册表是Windows特定API的原因。[SupportedOSPlatform]Microsoft.Win32.Registry
注意,如果你的目标是 ,这个属性会自动应用到你的程序集上。这意味着从使用Windows特定的API将永远不会产生任何警告,因为你的整个程序集被认为是Windows特定的net5.0-windows
.NET 5是.NET Standard和.NET Core的组合
.NET 5和后续版本将是一个单一的代码库,支持桌面应用、移动应用、云服务、网站,以及.NET明天将运行的任何环境。
你可能会想"等等,这听起来不错,但如果有人想创建一个全新的实现呢"。这也很好。但几乎没有人会从头开始创建一个。最有可能的是,它将是当前代码基础(dotnet/runtime)的一个分叉。例如,Tizen(三星的智能电器平台)使用的是.NET核心,改动很小,上面有三星特有的应用模型。
分叉保留了合并关系,这使得维护者可以继续从dotnet/runtime repo拉入新的变化,在未受其变化影响的领域从BCL创新中获益。这与Linux发行版的工作方式非常相似。
当然,在有些情况下,人们可能想创建一个非常不同的.NET"种类",比如一个没有当前BCL的最小运行时。但这意味着它不能利用现有的.NET库生态系统,这意味着它也不能实现.NET标准。一般来说,我们对追求这个方向不感兴趣,但.NET标准和.NET核心的融合并没有阻止这一点,也没有使它变得更难。
.NET版本划分
作为一个库的作者,你可能想知道.NET 5何时会被广泛支持。今后,我们将在每年的11月发布.NET,每隔一年发布一个长期支持(LTS)版本。
.NET 5将于2020年11月发布,.NET 6将于2021年11月作为LTS发布。我们创建这个固定的时间表是为了让你更容易计划你的更新(如果你是一个应用程序开发者)和预测对支持的.NET版本的需求(如果你是一个库的开发者)。
由于能够并排安装.NET Core,新版本的采用速度相当快,LTS版本最受欢迎。事实上,.NET Core 3.1是有史以来采用最快的.NET版本。
我们的期望是,每次发货时,我们把所有的框架名称连在一起发货。例如,它可能看起来像这样。
.NET 5 | .NET 6 | .NET 7 |
---|---|---|
net5.0 | net6.0 | net7.0 |
net6.0-android | net7.0-android | |
net6.0-ios | net7.0-ios | |
net5.0-windows | net6.0-windows | net7.0-windows |
net5.0-someoldos |
这意味着你通常可以期待,无论我们在BCL中做了什么创新,你都能从所有的应用模型中使用它,无论它们在哪个平台上运行。这也意味着,只要你运行最新版本的库,最新框架的库总是可以从所有应用模型中使用。
这种模式消除了围绕.NET标准版本的复杂性,因为每次我们发货时,你可以假设所有平台都会立即完全支持新版本。我们通过使用前缀命名惯例来巩固这一承诺。
.NET的新版本可能会增加对其他平台的支持。例如,我们将通过.NET 6增加对Android和iOS的支持。反之,我们可能会停止支持那些不再相关的平台。在.NET 6中不存在的假装目标框架就说明了这一点。我们没有放弃一个平台的计划,但这个模型支持它。这将是一个大问题,不是预期的,而且会提前很长时间宣布。这与我们在.NET Standard中的模式是一样的,例如,没有新版本的Windows Phone来实现后来的.NET标准。
目标框架(TFM)
目标框架(Target Framework Moniker, TFM)是一个标准化令牌格式,用于指定.NET应用或库的目标框架。目标框架通常由短名称(如net462
)引用。存在长格式的TFM(如.NET Framework,Version=4.6.2),但通常不用来指定目标框架。
目标框架 | 最新稳定版本 | 目标框架名字对象 (TFM) | 已实现.NET Standard 版本 |
---|---|---|---|
.NET 6 | 6 | net6.0 | 2.1 |
.NET 5 | 5 | net5.0 | 2.1 |
.NET Standard | 2.1 | netstandard2.1 | 空值 |
.NET Core | 3.1 | netcoreapp3.1 | 2.1 |
.NET Framework | 4.8 | net48 | 2 |
.NET 5及更高版本特定于OS的TFM
TFM | 可兼容对象 |
---|---|
net5.0 | net1..4(带有 NU1701 警告) |
netcoreapp1..3.1 (引用 WinForms 或 WPF 时出现警告) | |
netstandard1..2.1 | |
net5.0-windows | netcoreapp1..3.1(以及从 net5.0 继承的所有其他内容) |
net6.0 | (后续版本的 net5.0) |
net6.0-android | xamarin.android(以及从 net6.0 继承的所有其他内容) |
net6.0-ios | xamarin.ios(以及从 net6.0 继承的所有其他内容) |
net6.0-maccatalyst | xamarin.ios(以及从 net6.0 继承的所有其他内容) |
net6.0-macos | xamarin.mac(以及从 net6.0 继承的所有其他内容) |
net6.0-tvos | xamarin.tvos(以及从 net6.0 继承的所有其他内容) |
net6.0-windows | (后续版本的 net5.0-windows) |
net7.0 | (后续版本的 net6.0) |
net7.0-android | (后续版本的 net6.0-android) |
net7.0-ios | (后续版本的 net6.0-ios) |
net7.0-maccatalyst | (后续版本的 net6.0-maccatalyst) |
net7.0-macos | (后续版本的 net6.0-macos) |
net7.0-tvos | (后续版本的 net6.0-tvos) |
net7.0-windows | (后续版本的 net6.0-windows) |
实践理解
如何选择版本
https://dotnet.microsoft.com/zh-cn/platform/dotnet-standard#versions
前面提到从.Net 5+开始,微软就把.Net Standard的版本停留在2.1不再更新了,但是保持向前兼容。
.Net实现 | 1.0 | 1.1 | 1.2 | 1.3 | 1.4 | 1.5 | 1.6 | 2.0 | 2.1 |
---|---|---|---|---|---|---|---|---|---|
.NET | 5.0+ |
5.0+ |
5.0+ |
5.0+ |
5.0+ |
5.0+ |
5.0+ |
5.0+ |
5.0+ |
.NET Core | 1.0+ |
1.0+ |
1.0+ |
1.0+ |
1.0+ |
1.0+ |
1.0+ |
2.0+ |
3.0+ |
.NET Framework | 4.5+ |
4.5+ |
4.5.1+ |
4.6+ |
4.6.1+ |
4.6.1+ |
4.6.1+ |
4.6.1+ |
N/A |
Mono | 4.6+ |
4.6+ |
4.6+ |
4.6+ |
4.6+ |
4.6+ |
4.6+ |
5.4+ |
6.4+ |
Xamarin.iOS | 10.0+ |
10.0+ |
10.0+ |
10.0+ |
10.0+ |
10.0+ |
10.0+ |
10.14+ |
12.16+ |
Xamarin.Mac | 3.0+ |
3.0+ |
3.0+ |
3.0+ |
3.0+ |
3.0+ |
3.0+ |
3.8+ |
5.16+ |
Xamarin.Android | 7.0+ |
7.0+ |
7.0+ |
7.0+ |
7.0+ |
7.0+ |
7.0+ |
8.0+ |
10.0+ |
UWP | 8.0+ |
8.0+ |
8.1+ |
10.0+ |
10.0+ |
10.0.16299+ |
10.0.16299+ |
10.0.16299+ |
待定 |
Unity | 2018.1+ |
2018.1+ |
2018.1+ |
2018.1+ |
2018.1+ |
2018.1+ |
2018.1+ |
2018.1+ |
2021.2+ |
- 如果你使用.Net Standard同时兼顾.Net Framework 4.6.1+和.Net Core,那么还是推荐你使用2.0版本较好,因为2.1不准备实现了。
- 如果你使用.Net Standard同时兼顾UWP 10.0.16299+和.Net Core,那么还是推荐你使用2.0版本较好,因为2.1还没实现。
创建.Net Standard类库
打开Visual Studio创建新项目,筛选库
分类,可以看到一个就是类库
。