.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 || WINDOWS
            return true;
#else
            return false;
#endif
        }
    }

    public static (double Latitude, double Longitude) GetCoordinates()
    {
#if ANDROID
        return AndroidAPI();
#elif IOS
        return AppleAPI();
#elif WINDOWS
        return WindowsAPI();
#else
        throw new PlatformNotSupportedException();
#endif
    }
}

不同的 API

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

public class SkiaSharpImage
{
#if ANDROID
    public SkiaSharpImage(Android.Media.Image nativeImage) { /* ... */  }
#endif

#if IOS
    public SkiaSharpImage(NSImage nativeImage) { /* ... */ }
#endif

#if WINDOWS
    public 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,我觉得大家有必要了解一下:

-

精致码农

带你洞悉编程与架构

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

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 扫一扫,分享海报

许多技术人员在面对.NETFramework3.0/3.5大量的新知识、新技术的时候感到彷徨,对自己现有的技术知识是否过时会产生疑问,对新技术会产生抵触的情绪,其实,只要能学习到真正代表业界趋势的技术,花不太多的时间掌握新技术,乐趣就会随之产生。编写本书的一个目的就是要让读者认识到.NET3.5相关的新知识都是基于现有技术的,体会、掌握并应用这些新技术并不是难事。 第1章.NETFramework3.5简介 1.1.NETFramework3.5在.NET技术体系中的位置 1.2.NET3.5各部分的功能 1.3.NET3.5的组件 1.3.1WindowsPresentaionFoundation(WPF) 1.3.2WindowsCommunicationFoundation(WCF) 1.3.3WorkflowFoundation(WF) 1.4搭建.NET3.5的开发环境 1.4.1在WindowsXP/word/73225.htm' target='_blank'>2003/vista搭建开发环境 1.4.2相关工具 第2章.NET3.5的新功能 2.1.NET3.5概要 2.2新的.NET基础类型 2.3C#语言的强化 2.3.1C#基本语法增强 2.3.2LIYO(集成语言查询) 第3章WindowsPresentationFoundation基础知识 3.1WindowsPresentationFoundation(WPF)的概念 3.2XAML的概念 3.2.1命名空间 3.2.2代码后置文件 3.2.3调用.NET类库中的类来定义对象 3.2.4属性 3.3WPF的结构和相关的类库 3.4WPF应用程序的类型 3.4.1传统类型的视窗程序 3.5创建第一个WPF程序 第4章WPF程序的布局 4.1布局的基础知识 4.2StackPanel容器 4.3DockPanel容器 4.4Grid容器 4.4.1表格的高度和宽度 4.4.2ColumnSpan和RowSpan 4.4.3Grid的SharedSizeGroup 4.5Canvas容器 4.6文档布局 4.6.1WrapPanel 4.6.2TextBlock 4.6.3FlowDocument 4.7其他容器 4.8视图控制 4.9自定义布局 第5章WPF的控件 5.1控件模型 5.2WPF的控件树 5.3路由事件 5.4从属属性(DependencyProperty) 55处理交互行为 5.6基本控件的使用 5.6.1Button控件 5.6.2TextBox类控件 5.6.3列表控件 5.6.4Menu控件 5.6.5包容式控件 5.6.6Label和TextBlock 5.6.7其他控件 第6章资源和数据绑定 6.1在WPF中定义资源 6.1.1WPF中的嵌入式资源 6.1.2定义逻辑资源 6.2使用资源 6.3数据绑定基础 6.4集合的绑定 6.5DataProvider 6.6高级数据绑定操作 6.7使用CollectionViewSource进行排序和过滤 第7章让WPF程序支持样式和主题 7.1样式基础 7.1.1WPF样式的定义 7.1.2样式的作用 7.1.3样式的作用范围 7.2内联样式 7.3命名样式 7.4样式触发器 7.5控件模板 7.6主题 第8章WPF的绘图功能 8.12D图形基础 8.22D几何图形 8.3画刷和画笔 8.3.1画刷 8.3.2画笔 8.42D图形变换(Transform) 8.4.1平移变换 8.4.2缩放变换 8.4.3旋转变换 8.4.4斜移变换 8.4.5矩阵变换 8.4.6变换组(TFansformGroup) 8.52D图形特效 8.63D图形基础 8.6.1计算机图形学基础 8.6.2WPF的3D类型 8.73D变换 8.8WPF的动画支持 8.8.1Animation对象 8.8.2第一个动画 第9章WPF的多媒体 9.1对视频和音频的支持 9.1.1视频支持 9.1.2音频支持
参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值