.NET 5 的 Target Framework 详解[上篇]

作者:.NET Team
翻译:精致码农-王亮
原文:http://dwz.win/Q4v

我们希望极大地简化开发人员必须在项目文件和 NuGet 包中使用的「TFM」 (Target Framework Name, 目标框架名称)。这包括合并 .NET 5 和 .NET Standard 的概念,同时仍然可以使用 #if 来编写特定于操作系统的代码。本文解释了开发的动机和由此产生的开发者体验。

.NET 和大多数有二十年历史的技术一样,有很多历史遗留问题,特别是在产品命名和版本方面:.NET Framework, .NET Compact Framework, Silverlight, .NET Micro Framework, .NET Portable Class Libraries, .NET for Windows Store, .NET Native, .NET Core, .NET Standard 等等,这还不包括 Mono 系的产品。虽然 .NET 的这种演变是情有可原的,但它创造了一个巨大的学习成本:不计其数的概念。如果你是 .NET 的新手,你会从哪里开始?最新技术栈是什么?你可能会说,当然那是 .NET Core 了,但是新手们怎么可能只看名字就知道它是什么?

我们已经用 .NET Standard 简化了世界。在类库中,作者不必考虑用不同的“盒子”去包装不同的 .NET 实现。这是因为我们为不同的 .NET 实现统一了上层 API。具有讽刺意味的是,这导致我们不得不添加另一个大“箱子”,即 .NET Standard。

为了使未来的 .NET 生态更加健康地发展,我们必须减少“包装盒”的数量。我们也不想让 .NET 变得不那么灵活,但是我们想减少纯粹因为我们没有尽早地开源而导致的荒谬差异。例如,Mono/Xamarin/Unity 与 .NET Framework/Silverlight/UWP/.NET Core 基于不同的运行时和框架。我们已经开始使用 .NET Standard 消除 API 表面上的差异。.NET 5 的目标是将这些产品线聚合到单个产品技术栈上,从而统一它们的实现。

虽然我们在努力为开发者提供良好的开发体验,让你不必对不同种类的 .NET 编写不同的实现。但我们仍然不想完全抽象掉底层的操作系统,所以你将继续能够调用操作系统特定的 API,无论是通过 P/Invokes、WinRT, 还是 Xamarin 为 iOS 和 Android 提供的绑定。

现在想想那些开始使用这个技术栈的开发者,可以为 .NET 提供支持的任何平台编写任何应用程序,他们需要的是更快的找到文档和教程。为此,他们只需要知道两件事,就是他们的技术栈名称和版本。

让我们看看目前这是一个什么样的体验,以几个比较流行的 NuGet 包为例,作者必须编写:

有很多名称和版本号。如果没有“解码环”(译注:一种比喻),想知道谁与谁兼容是不可能的。我们已经用 .NET Standard 大大简化了这一点,但这仍然需要一个映射表将 .NET Standard 版本和 .NET 实现版本进行匹配。

我们的提议是通过新的语法重新使用现有的 net TFM 和操作系统特定的 API 模型:

net5.0,这个 TFM 是表示代码可以在任何环境运行,它结合并取代了 netcoreappnetstandard 的名称。这个 TFM 一般只包括跨平台的技术(像我们已经在 .NET Standard 中做的那样)。

net5.0-androidnet5.0-iosnet5.0-windows,这些 TFM 代表了 .NET 5 的特定操作系统,包括 net5.0 加上特定操作系统的绑定。

NuGet 应该使用这种新的语法来自动理解:在 net6.0-windows 中可以使用 net5.0(而反过来不行)。更重要的是,这种符号还能让开发人员直观地理解兼容性关系。

场景和用户体验

不同的实现

小花正在开发一个支持 Android、iOS 和 Windows 的 Xamarin Forms 应用程序。她的应用需要获取 GPS 信息,但只是针对非常有限平台。由于没有可移植的 GPS API,她使用 multi-target 写了自己的小抽象库。

通过这种方式,她能够封装 GPS 访问,而不必对整个应用进行 multi-target,只需在一个地方进行 multi-target 即可。

public static class GpsLocation
{public static bool IsSupported{get{
#if ANDROID || IOS || WINDOWSreturn true;
#elsereturn false;
#endif}}public static (double Latitude, double Longitude) GetCoordinates(){
#if ANDROIDreturn AndroidAPI();
#elif IOSreturn AppleAPI();
#elif WINDOWSreturn WindowsAPI();
#elsethrow new PlatformNotSupportedException();
#endif}
}

不同的 API

小花是 SkiaSharp 的开发者,SkiaSharp 是一个基于谷歌 Skia 图形库的 .NET 跨平台 2D 图形 API。该项目已经在使用 multi-target 来为不同平台提供不同的实现。为了让它更容易使用,她增加了一个新的 SkiaSharpImage 类型,它代表一个位图,并通过 OS 提供的数据类型来构造。小花使用 #if 在不同平台上暴露不同的构造函数:

public class SkiaSharpImage
{
#if ANDROIDpublic SkiaSharpImage(Android.Media.Image nativeImage) { /* ... */  }
#endif#if IOSpublic SkiaSharpImage(NSImage nativeImage) { /* ... */ }
#endif#if WINDOWSpublic SkiaSharpImage(Windows.Media.BitmapImage nativeImage) { /* ... */ }
#endif
}

更新 OS 绑定

小明正在构建一个叫 Baby Shark 的 iOS 应用。他一开始使用的是支持 iOS 13 的 .NET,但苹果刚刚发布了 iOS 14。他下载了更新版的 .NET 5 SDK,它包含了对 iOS 14 的支持。为了获得苹果添加的新 API 的访问支持,小明打开了他的项目文件,目前这个文件是这样的:

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net5.0-ios13.0</TargetFramework></PropertyGroup>...</Project>

他把 <TargetFramework> 修改为 net5.0-ios14.0

点亮新的 OS 版本

小明不想切断目前使用 iOS 13 的用户,所以他希望自己的应用也能继续在 iOS 13 上运行。为了达到这个目的,小明修改了项目文件,添加了 <SupportedOSPlatformVersion>

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net5.0-ios14.0</TargetFramework><SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion></PropertyGroup>...</Project>

不过,由于小明也使用了苹果在 iOS 14 中加入的新的 NSFizBuzz API,所以他也修改了自己的源代码,在调用之前检查 OS 版本:

public void OnClick(object sender, EventArgs e)
{if (Environment.OSVersion.Version >= new Version(14, 0)){NSFizBuzz();}
}

消费更高的 SupportedOSPlatformVersion 库

在直接使用 NSFizzBuzz 一段时间后,小明注意到这些操作系统的 API 有点难用,于是他开始寻找一个.NET 库。他找到了 Monkey.FizzBuzz,并尝试引用它,成功了。然而,当编译他的应用程序时,他得到以下警告:

warning NU1702: Package 'Monkey.FizzBuzz' was restored using 'net5.0-ios14' and has 'SupportedOSPlatformVersion' of '14.0' while the project has a value of '13.0'. You should either upgrade your project to '14.0' or only make calls into the library after checking that the OS version is '14.0' or higher.

由于小明已经对所有的方法调用进行了保护,所以他只是取消了警告(译注:可以在项目文件中通过<NoWarn>设置)。

消费更高的 TargetPlatformVersion 库

小明在他的 Baby Shark 应用中成功使用 Monkey.FizzBuzz 后,小明想在其它地方也使用它,所以他决定在他现有的 Laserizer 5000 应用中使用它。然而,当他添加对 Monkey.FizzBuzz 的引用时,他得到一个 NuGet 引用错误:

error NU1202: Package 'Monkey.FizzBuzz' is not compatible with 'net5.0-ios13.0'. Package 'Monkey.FizzBuzz' supports: net5.0-ios14.0

所以小明修改了他的项目文件,将 net5.0-ios13.0 改为 net5.0-ios14.0,从而解决了这个错误。

使用比当前 SDK 更高的 TargetPlatformVersion

小翠的环境安装的是第一个版本的 .NET 5 SDK,它只提供到 iOS 13 的支持。她从 GitHub 上克隆了小明的 Baby Shark 仓库,并试图在她的机器上编译它。由于 Baby Shark 的目标是 net5.0-ios14.0,她得到了一个编译错误:

error NETSDK1045: The current .NET SDK does not support targeting iOS 14.0. Either target iOS 13.0, or use a version of the .NET SDK that supports iOS 14.0. [BabyShark.csproj]

要求

目标

  • 使用与产品战略一致的命名;

  • 将 .NET Core 和 .NET Standard 合并为一个概念;

  • 开发人员应该能够理解兼容性关系,而不必查阅映射表;

  • 提供与现有概念和 NuGet 包的兼容性;

  • 如果能在 .NET 5 的早期预览版中加入这个功能就再好不过了;

  • 支持同一操作系统的不同版本的 multi-target;

  • 不强迫同一操作系统应用不同版本的 multi-target。当调用被操作系统的检查保护时,应当能够产生一个可以使用较新 API 的二进制文件。

非目标

  • 换 TFM 或扩大运行时标识符(RID)

未完待续

译注:文章太长,今天先翻译一半,有空再继续翻译。后一半主要讲 TFM 的设计细节,比如多个 TFM 选择的优先级、 MSBuild 的属性(TFI、TFV、TFP、TPI、TPV 等)、NuGet 包的行为等。其中比较重要的是下面这张表,它列出了现有的 TFM,我觉得大家有必要了解一下:

-

精致码农

带你洞悉编程与架构

↑长按图片识别二维码关注,不要错过网海相遇的缘分

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307628.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode1143. 最长公共子序列

一&#xff1a;题目 二:上码 class Solution { public:/**思路:1.分析题意这个子序列就是我们是可以不连续的字符组成的2.动态规划五步走1>:确定dp数组的含义以及下标的含义dp[i][j] 表示的是text1中[0,i-1]字符范围,text2中[0,j-1]的字符范围 的最长公共子序列这里我们取i…

JAVA 15发布,越来越像C# ?9月排名,C#增幅狠甩JAVA

2016年.NET Core首个正式版本问世&#xff0c;如今已发布到了.NET Core3.1&#xff0c;再有2个月.NET5也将如约而至&#xff0c;跨平台开发已经快5年。微软 .NET 程序管理总监 Scott 表示&#xff0c;.NET 5 是 .NET Framework 和 .NET Core 的未来&#xff0c;最终将成为一个统…

leetcode1035. 不相交的线

一:题目 二:上码 class Solution { public:/**思路:1.分析题意:这里的我们要求解的是最大值,那么我们的求解过程肯定是动态变化的,举个例子2 5 1 2 510 5 2 1 5 2 如果我们一开始就让nums1[1] 5何 nums2[4] 5 相连的话 那么我们肯定不会求解出最大值那么题目中的说的直线不…

几个超级实用但很少人知道的 VS 技巧[更新]

大家好&#xff0c;今天分享几个我知道的实用 VS 技巧&#xff0c;而这些技巧我发现很多人都不知道。因为我经常在工作中遇到&#xff1a;我在同事电脑上解决问题&#xff0c;或在会议上演示代码示例时&#xff0c;使用了一些 VS “骚”操作&#xff0c;他们会好奇地问&#xf…

leetcode53. 最大子数组和(动态规划)

一:题目 二:上码 class Solution { public:int maxSubArray(vector<int>& nums) {/**动态规划:1>:确定dp数组的含义以及下标的含义dp[j]表示的是下标j之前的最大子数组和 这个就是还没有包括nums[j] 2>:确定dp数组的状态转移公式dp[j] max (dp[j-1]nums[j],n…

基于REACT和.NET CORE集成WINDOWS身份验证

有很多方法可以向您的应用程序添加身份验证。虽然OAuth是最常见的一种&#xff0c;但这并不是您唯一的选择。今天&#xff0c;我将向您展示如何通过React和.NET Core简单地完成Windows身份验证。探索我们的选择在深入探讨之前&#xff0c;让我们简要讨论一些可用的其他选项。了…

.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书

简介加解密现状&#xff0c;编写此系列文章的背景&#xff1a;需要考虑系统环境兼容性问题&#xff08;Linux、Windows&#xff09;语言互通问题&#xff08;如C#、Java等&#xff09;&#xff08;加解密本质上没有语言之分&#xff0c;所以原则上不存在互通性问题&#xff09;…

leetcode115. 不同的子序列

一&#xff1a;题目 二:代码 class Solution { public:/**思路:动规分析走一波1>:确定dp数组以及下标的含义dp[i][j] 表示的是 以下标i-1结尾的子序列s中出现以j-1结尾的子序列t的 个数2>:确定dp数组的状态递推公式这里考虑两种状况 一种就是 s[i-1] s[j-1] 一种就是字…

ASP.NET Core 3.x启动时运行异步任务(二)

这一篇是接着前一篇在写的。如果没有看过前一篇文章&#xff0c;建议先去看一下前一篇&#xff0c;这儿是传送门一、前言前一篇文章&#xff0c;我们从应用启动时异步运行任务开始&#xff0c;说到了必要性&#xff0c;也说到了几种解决方法&#xff0c;及各自的优缺点。最后&a…

leetcode583. 两个字符串的删除操作

一:题目 二:上码 class Solution { public:/**思路:题目给的是让求最值,那么首先就会想到的是动态规划,我们想得到答案的结果其实有多个的&#xff0c;但是我们是取最小的步数动态规划 五步走:1>:确定dp数组以及下标的含义dp[i][j]表示的是 以下标i-1结尾的字符串word1,和…

C# 中居然也有切片语法糖,太厉害了

一&#xff1a;背景 1. 讲故事昨天在 github 上准备找找 C# 9 又有哪些新语法糖可以试用&#xff0c;不觉在一个文档上看到一个很奇怪的写法: foreach (var item in myArray[0..5]) 哈哈&#xff0c;熟悉又陌生&#xff0c;玩过python的朋友对这个 [0..5] 太熟悉不过了&#x…

跟我一起学.NetCore之中间件(Middleware)简介和解析请求管道构建

前言中间件(Middleware)对于Asp.NetCore项目来说&#xff0c;不能说重要&#xff0c;而是不能缺少&#xff0c;因为Asp.NetCore的请求管道就是通过一系列的中间件组成的&#xff1b;在服务器接收到请求之后&#xff0c;请求会经过请求管道进行相关的过滤或处理&#xff1b;正文…

leetcode647. 回文子串

一&#xff1a;题目 二&#xff1a;上码 class Solution { public:/**思路:动态规划五步走1>:确定dp数组以及下标的含义dp[i][j] 表示的是在[i,j]范围内的字串 是否是 回文子串&#xff0c;如果是的话那么dp[i][j] true2>确定dp数组的状态转移方程那么就有两种情况 s[i…

leetcode516. 最长回文子序列

一:题目 二:上码 class Solution { public:/**思路:1.分析题意 这个是让我们求最值,那么首先想到动态规划2.动态规划1>:确定dp数组以及下标的含义dp[i][j] 表示字符串在[i,j]范围内的最长回文子序列2>:确定dp数组的状态递推公式那么就是s[i] 与 s[j] 相等 不相等两种情况…

C#刷剑指Offer | 二叉搜索树的后序遍历序列

【C#刷题】| 作者 / Edison Zhou这是EdisonTalk的第289篇原创内容我们来用之前学到的数据结构知识来刷《剑指Offer》的一些核心题目&#xff08;精选了其中30道题目&#xff09;&#xff0c;希望对你有帮助&#xff01;本文题目为&#xff1a;二叉搜索树的后序遍历序列。1题目介…

leetcode739. 每日温度

一:题目 二:上码 // class Solution { // public: // vector<int> dailyTemperatures(vector<int>& temperatures) { // vector<int> ans(temperatures.size(),0);// for (int i 0; i < temperatures.size(); i) {// …

Leetcode周赛复盘——第 71 场力扣双周赛与第 279 场力扣周赛

双周赛&#xff1a; 5984. 拆分数位后四位数字的最小和 class Solution:def minimumSum(self, num: int) -> int:a, b, c, d sorted(list(map(int, str(num))))return 10 * (a b) c dstr(num)得到字符串序列&#xff0c;然后用map函数对序列的每个字符转换为数字&…

使用SWAGGER和ASP.NET CORE设置可选路由参数

使用SWAGGER和ASP.NET CORE设置可选路由参数根据OpenAPI 3.0&#xff0c;这是不可能的。但是&#xff0c;如果您真的希望成为现实呢&#xff1f;您是否必须解决并允许您的Swagger文档出错&#xff1f;我在这里向您展示如何使用Swagger和ASP.NET Core设置可选的路由参数。等等&a…

在数组中找重复数、只出现一次的数或丢失数的题目(Leetcode题解-Python语言)

在一维数组中的考察中&#xff0c;最常见的就是找出数组中的重复数、只出现一次的数或者丢失&#xff08;消失&#xff09;数等等。 一般来说&#xff0c;首先想到的就是用哈希表&#xff08;集合&#xff09;来记录出现过的数&#xff0c;基本所有的题都可以用集合来做&#…

Confluent官博:Kafka最牛队列,性能15倍于RabbitMQ!

“容器、Kubernetes、DevOps、微服务、云原生&#xff0c;这些技术名词的频繁出现&#xff0c;预兆着新的互联网技术时代的到来&#xff0c;大数据高并发将不再遥远&#xff0c;而是大部分项目都必须面对的&#xff0c;消息队列则是核心利器&#xff01;成熟的消息队列产品很多…