使用 LatestCSharpFeatures 库让旧版本 dotnet 框架项目使用新 C# 语法

news/2024/12/14 7:12:05/文章来源:https://www.cnblogs.com/lindexi/p/18606279

背景

众所周知,在咱 dotnet 体系里面,框架和语言版本是分离的。即使 C# 的版本支持情况只和编译器有关,而与运行时版本无直接关系

换句话说就是即使现在还在使用老旧的 .NET Framework 4.5 的 dotnet 版本,也依然可以使用 C# 13 甚至更高版本的语法

但为什么有时候会给一些新手以错觉,认为 C# 语言版本是跟随 dotnet 版本走的?这个错觉是因为有两个主要问题导致的

首要问题是 dotnet 是分 SDK 和运行时这两个东西,编译器是放在 SDK 里面,即至少 SDK 版本需要更加新的版本才能支持更加新的 C# 语法。但 SDK 是跑在开发者的电脑上的,版本新或高是没有任何问题的,新的 SDK 高版本是完全可以构建出旧的 dotnet 版本的项目的。运行时是跑在用户设备上的,如上文举例的 .NET Framework 4.5 的 dotnet 版本,一般而言指的是配置在 csproj 项目里面,指定运行时版本,运行时版本可以旧一些。用新的 SDK 高版本构建旧的运行时的应用是完全没有问题的,整个 dotnet 体系的兼容性就是做的这么好。有些新手开发者分不清 SDK 版本和运行时版本,错将用于构建的 SDK 版本号当成运行时版本号,从而有了认为 C# 语言版本是跟随 dotnet 版本走的错误知识

次之的原因是高版本的 C# 语言可能用到了一些类型,这些类型是只有在新版本的 dotnet 框架里才有定义的。这就导致了默认情况下,由于有些语法对应的类型在低版本 dotnet 框架找不到,从而导致开发者无法在低版本的 dotnet 使用高版本 C# 语法

本文和大家介绍的 dotnet campus 开源组织的 LatestCSharpFeatures 库正是用来解决上文次之的原因提到的问题,通过 LatestCSharpFeatures 库补全缺失的 C# 高版本语法所需的类型,从而让低版本的 dotnet 项目可以放心使用高版本 C# 语法

仓库开源地址: https://github.com/dotnet-campus/dotnetCampus.LatestCSharpFeatures

用法

按照 dotnet 的惯例,第一步是安装 NuGet 包: https://www.nuget.org/packages/dotnetCampus.LatestCSharpFeatures

对于这个库来说,就没有第二步了,安装完成之后,即可在项目里面放心使用高版本 C# 语法了

这个 LatestCSharpFeatures 库的版本号有一个特殊约定,那就是第一位主版本号就是对应的 C# 语法版本号了哈

原理

既然用法如此简单,那自然就有伙伴好奇这个库的原理了。其实在 LatestCSharpFeatures 库里面是没有什么科技的,真正的科技都在 C# dotnet 这边

按照 C# 和 dotnet 的设计,语言是独立于框架的存在,也就是 C# 是独立于 dotnet 的存在。在构建过程中,高版本 C# 语法所需的一些类型,只需要这些类型能够被找到即可。类型能够被找到只需满足命名空间和类型名符合约定即可,至于这个类型具体放在哪里,这不是编译器所关心的。这就意味着高版本 C# 语法所需的辅助类型,只要在项目里面有能找到定义就好了,至于具体是放在 dotnet 运行时里还是在项目里面定义的,那都随意。通过如此设计,即可让 C# 和 dotnet 进一步分离,尽管要实现某些 C# 甜甜语法,需要用到一些辅助类型,但是没有规定这些类型一定要在 dotnet 基础库里面找到

额外的,如上文所述规定,只是要求满足命名空间和类型名符合约定,完全没有要求访问权限是什么,也就是在项目里面放 internal 还是 public 的辅助类型,都是可以的

基于 C# 和 dotnet 的如此巧妙的设计,自然就可以很方便写出一个源代码生成器项目,让源代码生成器生成高版本 C# 所需的辅助类型,再配合默认的条件编译符的方式,只在低版本的 dotnet 项目开放代码内容。如此即可让低版本的 dotnet 项目使用高版本的 C# 语法

举个例子,在 C# 9 引入的 init 语法,就要求存在 System.Runtime.CompilerServices.IsExternalInit 辅助类。这个 IsExternalInit 辅助类型是在 dotnet 5 引入的。如果要在 .NET Core 3.1 的项目上使用 init 语法,可以在自己的项目上添加以下代码

using System.ComponentModel;namespace System.Runtime.CompilerServices
{/// <summary>/// Reserved to be used by the compiler for tracking metadata./// This class should not be used by developers in source code./// This dummy class is required to compile records when targeting .NET Standard/// </summary>[EditorBrowsable(EditorBrowsableState.Never)]internal static class IsExternalInit{}
}

在 LatestCSharpFeatures 库里面,就使用源代码生成器技术,将以上代码塞入到项目里面

可能此时大家有疑惑,那如果我的项目是 dotnet 6 框架的呢?这里塞入的 IsExternalInit 类型会不会和 dotnet 基础库提供的冲突了?答案是如果就只有以上代码,那肯定是冲突的。为了解决冲突,就加上条件编译符,加上之后的代码如下

#if NET5_0_OR_GREATER
#else
using System.ComponentModel;namespace System.Runtime.CompilerServices
{/// <summary>/// Reserved to be used by the compiler for tracking metadata./// This class should not be used by developers in source code./// This dummy class is required to compile records when targeting .NET Standard/// </summary>[EditorBrowsable(EditorBrowsableState.Never)]internal static class IsExternalInit{}
}
#endif

先判断当前的框架版本是多少,如果是 .NET 5 或更高版本,则啥都不用干。否则加塞进入 IsExternalInit 类型

通过如此方式即可实现让低于 dotnet 5 版本的项目使用到 C# 9 的 init 语法

喜欢探寻研究技术的伙伴也许会有更多疑惑,为什么我知道可以使用 NET5_0_OR_GREATER 条件编译符来判断当前的框架版本?源代码生成器是如何实现的?我在以下附加了一些链接,希望能帮助大家

  • dotnet 新项目格式与对应框架预定义的宏
  • 尝试 IIncrementalGenerator 进行增量 Source Generator 生成代码

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

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

相关文章

【Hadoop框架】生态组件之分布式文件系统 HDFS 可视化界面

一、Overview 二、Datanodes 三、Datanode Volume Failures 四、Snapshot 五、Startup Progress 六、Utilities6.1 Browse the file system6.2 Logs6.3 Log Level6.4 Metrics6.5 Configuration6.6 Process Thread Dump6.7 Network TopologyHDFS 提供了 Web 管理界面,可以很方便…

【Hadoop框架】Yarn 核心组件+工作流程+基本使用

一、Yarn的基本概念和架构二、Yarn的工作流程三、Yarn的核心组件及其功能 ‌ 3.1 ResourceManager‌3.2 NodeManager3.3 ApplicationMaster四、Yarn的基本使用4.1 Yarn Shell 命令4.2 Yarn Shell 使用示例4.2.1 首先确定 Yarn 集群启动4.2.2 发起任务4.2.3 查看任务4.2.4 终止…

基于中间畸变流估计的滚动快门校正

基于中间畸变流估计的滚动快门校正提出通过直接估计从全局快门(GS)到滚动快门(RS)的失真,来校正滚动快门(SS)失真的图像。现有的方法通常使用从RS到GS的未失真流进行校正。它们最初从连续的RS帧预测流,随后使用时间相关的缩放因子将其重新缩放为从RS帧到底层GS图像的位…

鸿蒙NEXT开发案例:颜文字搜索器

【引言】 本文将介绍一个名为“颜文字搜索器”的开发案例,该应用是基于鸿蒙NEXT平台构建的,旨在帮助用户快速查找和使用各种风格的表情符号。通过本案例的学习,读者可以了解如何在鸿蒙平台上进行数据处理、UI设计以及交互逻辑的实现。 【环境准备】 • 操作系统:Windows 10…

CycleINR:任意尺度医学数据三维超分辨率的循环隐式神经表示

CycleINR:任意尺度医学数据三维超分辨率的循环隐式神经表示在医学3D数据领域,如CT和MRI图像,普遍的各向异性分辨率的特点是层内分辨率高,但层间分辨率低。相邻切片之间的分辨率降低带来了挑战,阻碍了最佳的观看体验,并阻碍了稳健的下游分析算法的发展。各种体积超分辨率算…

用于大规模单像素成像的双尺度变换器

用于大规模单像素成像的双尺度变换器单像素成像(SPI)是一种潜在的计算成像技术,通过解决单像素探测器捕获的少量测量值中的病态重建问题来产生图像。深度学习在SPI重构方面取得了令人瞩目的成功。然而,之前较差的重建性能和不切实际的成像模型,限制了其在现实世界中的应用…

应用题3

这道题知识点参考书116页二叉树遍历相关知识。 知识点:二叉树中序遍历,后序遍历的顺序是什么如何将一棵二叉树转化为树(或森林)中序遍历(左->根->右)后序遍历(左->右->根)根据中序遍历和后序遍历的特点,我们可以知道,中序遍历中根节点在中间,后序遍历中…

河北知识付费系统热门课程是什么

在当今科技快速发展的社会环境中,教育领域也随之发生着深刻的变革。尤其是随着互联网及数字媒体的应用日渐普及,知识付费及在线教育成为了新时代学习者的优选途径。河北的知识付费系统通过其丰富的教学资源与创新的教学模式满足了不同年龄、层次的学习者多样化的需求。为了回…

转载:【AI系统】AI 框架作用

深度学习范式主要是通过发现经验数据中,错综复杂的结构进行学习。通过构建包含多个处理层的计算模型(网络模型),深度学习可以创建多个级别的抽象层来表示数据。例如,卷积神经网络 CNN 可以使用大量图像进行训练,例如对猫狗分类去学习猫和狗图片的特征。这种类型的神经网络…

转载:【AI系统】卷积操作原理

卷积是神经网络里面的核心计算之一,它是一种特殊的线性运算。而卷积神经网络(CNN)是针对图像领域任务提出的神经网络,其受猫的视觉系统启发,堆叠使用卷积层和池化层提取特征。它在 CV 领域方面的突破性进展引领了深度学习的热潮。 回到卷积本身,其变种丰富、计算复杂,神…

转载:【AI系统】Winograd 算法

在上一篇文章的介绍中,介绍了 Im2Col 技术,它通过将三维张量重新排列成矩阵形式,然后利用基于内存访问局部性的优化库如 GEMM(通用矩阵乘法库)加速计算。随后,还探讨了空间组合优化,这一种利用局部性原理来提升效率的技术。 在本文将重点介绍 Winograd 优化算法,它是矩…

转载:【AI系统】Im2Col 算法

作为早期的 AI 框架,Caffe 中卷积的实现采用的是基于 Im2Col 的方法,至今仍是卷积重要的优化方法之一。 从上一篇文章的介绍中可以看到,在 CNN 中卷积直接计算的定义中,卷积核在输入图片上滑动,对应位置的元素相乘后相加求和,滑窗的大小由卷积核决定。由于滑动操作时的窗…