【C#杂谈】在 .NET Framework 中使用新的C#语言特性

前排提示:提出一个可以让 [^1] 这中语法可以在.NET Framework运行时中使用的方法

众所都周知,.NET Framework(以下简称 .NF)作为一个被微软官方确认不在继续发布新特性的运行时,它所对应的C#语言版本被(官方形式上)永久地停更在了 C# 7.3(对应着 .NF 4.8,如果是更早版本的 .NF,那么其语言版本可能更古早)。

但是,由于C#是语言,而.NF是实现该语言的运行时,如果某些语言特性能够在 .NF 的框架下实现,那么我们实际上还是能在 Visual Studio 等IDE上直接通过修改对应的 .csproj 文件,增加 <LangVersion>,来使用新的语言特性的。

运行时与语言的关系就类似于……我用口头说话来指挥雇佣工干活,我说的话(语言)和他能干的活(运行时)一般来说是没有一一对应的关系的。

C#更高级的语言可以认为是我会更多的词汇,但是如果这个词汇所代表的特性能够被现有的运行时来实现,那么新版本的C#语言也是可以使用 .NF 来编译运行。

比如我比较喜欢的 Pattern Matching enhancements (C# 9.0),就能让我们在代码里使用 is not 的关键词。

if (e is not string { Length: > 5} short_str)
{// ... 如果e不满足“非空”且“长度大于5”的条件
}

这本质上是一些语法糖,所以 .NF 是支持这些语法的。

微软官方对于这些通过改 .csproj 文件就能实现的功能具体有哪些并没有写明的文档可以参考,有的只是运行时对应的“保证语言特性100%支持的版本”,它列在了下面的网页中。

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version

C# 12 is supported only on .NET 8 and newer versions. C# 11 is supported only on .NET 7 and newer versions. C# 10 is supported only on .NET 6 and newer versions.

我们知道当然不是如此,某些C# 12的功能也能在 .NF 下使用,比如 Primary constructors(前提是更新 Visual Studio 2022 到版本 17.6 以上,总之更新到最新就对了)。

C#语言的新功能在新的运行时能力加持下,可能会带来执行速度的提升,但是在旧的运行时版本下,可能只是语法糖。

不过!就算是语法糖,那也能极大地提高代码可读性,减少出错,比如上面的 e is not string,那就比 !(e is string) 更容易理解,因为后者再叠加上if,就变成了

if (!(e is string))

布尔取反被夹在了俩括号之间,不小心就看错了,尤其是对新手而言。我认为一个好的高级语言一定是能够帮助程序员更加专注于业务逻辑而非语法本身的。所以,这种新特性虽然不能提高执行效率,但我仍然推荐大家使用。

下面我就稍微列一下我个人最喜欢的语言特性【排名部分先后】:

  1. 模式匹配 https://learn.microsoft.com/zh-cn/dotnet/csharp/fundamentals/functional/pattern-matching
  2. 主构造函数 https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/tutorials/primary-constructors
  3. 全局using指令 https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-10#global-using-directives
  4. 原始字符串文本 https://learn.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-11#raw-string-literals
  5. 从末尾运算符 ^ 开始索引 https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/member-access-operators#index-from-end-operator-

俗话说,重要的事情留到最后,没错,今天的主角就是 5. 从末尾运算符 ^ 开始索引

^ 是个啥

相信很多读者必写过这样的代码:

var last = list[list.Count - 1];

噢!那丑陋的.Count - 1 。如果变量名再长点,再多点额外的业务逻辑:

var diff = some_sort_of_list[some_sort_of_list.Count - 2] - some_sort_of_list[some_sort_of_list.Count - 1];

一般在写这种东西的时候我就已经开始换行了。这个时候有些人就想起了 System.Linq 命名空间里的 Last() 方法。它确实可以拯救 .Count - 1,但是这救不了 .Count - 2啊!。

C# 8 中就有一个解决这个问题的方法,用 [^1] 来代表向前数倒数第一个,[^n] 就代表倒数第n个。这也太直观了。

var diff = some_sort_of_list[^2] - some_sort_of_list[^1];

方便阅读,不会出错。

但是!!! 事情并没有那么简单。如果直接新建一个 .NET Framework 的 命令行项目,修改 <LangVersion>latest(使用最新)

在这里插入图片描述

Main 函数里写下下面的代码,我们会发现无法编译,IDE会报一个很奇怪的错误:

在这里插入图片描述

System.Index类找不到”、“缺失编译器需要的成员…ctor”,这都什么错误??

解决 [^1] 无法编译的问题

这个问题其实就是 .NF 框架的问题。C# 8.0的这个 “从后往前数” 的新的语言特性需要运行时中包含有一个System.Index类,这样它在编译的时候就直接用这个类去支持该特性了。但是由于 .NF 的运行时默认不包含该类,那就自然无法直接使用该语言特性了。

简而言之,就是[^1]这种语法需要运行时包含System.Index类,但是.NF中内置没有包含,所以GG。

不过,既然本节的标题是“解决”,那么事情必然是有转机的。在笔者翻了外网各种奇奇怪怪的论坛之后,得出的结论是“如果.NF没有这个类,那么我们自己提供一个就可以了!!! ”。

妙啊!

直接新建一个类,起名 Index.cs,粘贴入大佬的代码(见本文最后)………… 编译通过,运行成功!

在这里插入图片描述

这回,代码可读性又更强了。【聪明的读者已经去尝试 范围运算符 了】

// Modified after: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Index.cs
// MIT licensed.
#if !NETCOREAPP3_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace System;
[EditorBrowsable(EditorBrowsableState.Never)]
public readonly struct Index : IEquatable<Index>
{private readonly int m_value;[MethodImpl(MethodImplOptions.AggressiveInlining)]public Index(int value, bool fromEnd = false){if (value < 0){throw new ArgumentOutOfRangeException(nameof(value));}if (fromEnd){m_value = ~value;}else{m_value = value;}}private Index(int value){m_value = value;}public static Index Start => new Index(0);public static Index End => new Index(~0);public int Value => m_value < 0 ? ~m_value : m_value;public bool IsFromEnd => m_value < 0;public static implicit operator Index(int value) => FromStart(value);public static bool operator ==(Index left, Index right) => left.Equals(right);public static bool operator !=(Index left, Index right) => !(left == right);[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Index FromStart(int value){if (value < 0){throw new ArgumentOutOfRangeException(nameof(value));}return new Index(value);}[MethodImpl(MethodImplOptions.AggressiveInlining)]public static Index FromEnd(int value){if (value < 0){throw new ArgumentOutOfRangeException(nameof(value));}return new Index(~value);}[MethodImpl(MethodImplOptions.AggressiveInlining)]public int GetOffset(int length) => IsFromEnd ? m_value + length + 1 : m_value;public override bool Equals(object value) => value is Index && m_value == ((Index)value).m_value;public bool Equals(Index other) => m_value == other.m_value;public override int GetHashCode() => m_value;public override string ToString() => IsFromEnd ? ToStringFromEnd() : ((uint)Value).ToString();private string ToStringFromEnd() => '^' + Value.ToString();
}
#endif

大佬代码出处(上面贴出来的代码删掉了注释并改了原来的一个小问题):

https://github.com/CptWesley/BackwardsCompatibleFeatures/blob/master/src/BackwardsCompatibleFeatures/Index.cs

关于范围运算符和其他类似的特性,原理也是一样的。找到对应的System.Range类,再额外提供几个方法就可以实现了。

在这里插入图片描述

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

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

相关文章

RabbitMQ架构详解

文章目录 概述架构详解核心组件虚拟主机&#xff08;Virtual Host&#xff09;RabbitMQ 有几种广播类型 概述 RabbitMQ是⼀个高可用的消息中间件&#xff0c;支持多种协议和集群扩展。并且支持消息持久化和镜像队列&#xff0c;适用于对消息可靠性较高的场合 官网https://www.…

uniapp富文本编辑-editor-vue2-vue3-wangeditor

前言 除了“微信小程序”&#xff0c;其他小程序想要使用editor组件实现富文本编辑&#xff0c;很难vue3项目 官方组件editor&#xff0c;在初始化时有点麻烦&#xff0c;建议搭配第三方组件wangeditor 写在前面 - editor组件缺少editor-icon.css 内容另存为editor-icon.css…

服务器租用和托管的区别

目前对于服务器要求相对高的企业会希望使用独立服务器来运行自己的网站&#xff0c;而在选择独立服务器业务事&#xff0c;是使用服务器托管还是服务器租用这两种方法时&#xff0c;许多刚进入网络或者传统行业的从业者&#xff0c;都不太了解什么是服务器&#xff0c;现在我来…

系统安全保证措施-word

【系统安全保证措施-各支撑材料直接套用】 一、 身份鉴别 二、 访问控制 三、 通信完整性、保密性 四、 抗抵赖 五、 数据完整性 六、 数据保密性 七、 应用安全支撑系统设计 软件全套资料下载进主页。

JProfiler详解 JVM性能监测内存泄露分析工具

JProfiler详解 JProfiler简介主要功能特点使用场景注意事项使用案例使用步骤Could not verify ssh-ed25519 host key with fingerprint 问题解决内存泄露分析 JProfiler简介 JProfiler是一款业界领先的Java性能分析工具&#xff0c;由ej-technologies公司开发&#xff0c;专门…

STM32自学☞WDG(看门狗)及其案例

一、WDG简介 由于看门狗的代码很少所以就直接在main主函数中写了&#xff0c;没单独建文件 二、独立看门狗 涉及的按键可参考之前的key.c和key.h文件 独立看门狗配置流程&#xff1a; 1.开启时钟&#xff08;LSI&#xff09; 2.解除IWDG_PR和IWDG_RLR的写保护 3.写入预分频和重…

【C++】什么是类与对象?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 面向对象概述 封装 继承 多态 类 类是什么? C中类的引入 C中类的定义 类的两种定义方式: 1.声明和定义全部放在类体中 2.类声明与成员函数定义分别放在不同的工程文件中…

Qt开发QHostInfo主机地址查询组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QHostInfo组件实现对主机地址查询功能…

三井住友保险中国区信息技术部负责人陈婧,将出席“ISIG-RPA超级自动化产业发展峰会”

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;RPA中国、AIGC开放社区、LowCode低码时代&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索R…

用一个 Python 脚本实现依次运行其他多个带 argparse 命令行参数的 .py 文件

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 问题描述&#xff1a;在 Windows 环境中&#xff0c;您希望通过一个 Python 脚本来实现特定的自动化任务&#xff0c;该任务需要依次运行其他多个带 argparse 命令行参数的 .py 文件。您希望找到一种简…

手写分布式配置中心(六)整合springboot(自动刷新)

对于springboot配置自动刷新&#xff0c;原理也很简单&#xff0c;就是在启动过程中用一个BeanPostProcessor去收集需要自动刷新的字段&#xff0c;然后在springboot启动后开启轮询任务即可。 不过需要对之前的代码再次做修改&#xff0c;因为springboot的配置注入value("…

C++命名空间详解

目录 C的由来&#xff1a; C语言的命名缺陷&#xff1a; 什么是命名空间&#xff1f; 命名空间的访问方式&#xff1a; 1、指定访问 2、展开命名空间&#xff08;慎用&#xff09; 相关知识&#xff1a; C的由来&#xff1a; C原来本质上是在C的基础上补充的语法&#x…

ARM单片机中程序在ROM空间和RAM空间的分布(分散加载文件,Scatter-Loading Description File)

对于 K e i l u V i s i o n I D E Keil\quad uVision\quad IDE KeiluVisionIDE&#xff0c;程序编译好之后&#xff0c;代码的下载位置&#xff08; R O M ROM ROM空间&#xff09;以及代码运行的时候使用的 R A M RAM RAM空间&#xff08; R A M RAM RAM空间&#xff09;默认…

下载一些ROS的包的方式

ROS Index 我们可以去ROS Index网站下载一些我们需要的包。打开浏览器在网址框输入index.ros.org。或者点击此处链接ROS Index 在这个网站中我们可以浏览并找到我们需要的包&#xff0c;也可以下载它的源代码或者仅安装到我们的系统中来使用。&#xff08;安装过程在终端中进行…

植物病虫害:YOLO水稻虫害识别数据集(6类,五千余张图像,标注完整)

YOLO水稻虫害识别数据集&#xff0c;包含褐飞虱&#xff0c;绿叶蝉&#xff0c;正常叶片&#xff0c;稻虫&#xff0c;二化螟&#xff0c;蝇蛆6个类别&#xff0c;共五千余张图像&#xff0c;yolo标注完整。 适用于CV项目&#xff0c;毕设&#xff0c;科研&#xff0c;实验等 …

零、自然语言处理开篇

目录 0、NLP任务的基础——符号向量化 0.0 词袋模型 0.1 查表/One-hot编码 0.2 词嵌入模型/预训练模型 0.2.0 Word2Vec &#xff08;0&#xff09;CBOW &#xff08;1&#xff09;Skip-gram 0.2.1 GloVe 0.2.2 WordPiece 0.2.3 BERT 0.2.4 ERNIE NLP自然语言处理&am…

Java 的 System 类常用方法介绍

Java 中的 System 类是一个final类&#xff0c;它提供了与系统相关的属性和方法。它是一个内置的类&#xff0c;可以直接使用&#xff0c;不需要实例化。System 类提供了标准输入、标准输出和错误输出流&#xff0c;以及对外部定义的属性和系统环境的访问。下面是 System 类的一…

LCR 132. 砍竹子 II

解题思路&#xff1a; 由于数量级较大&#xff0c;需要使用long以及快速幂求余 下图便于理解快速幂求余 class Solution {public int cuttingBamboo(int bamboo_len) {if(bamboo_len < 3) return bamboo_len - 1;int b bamboo_len % 3, p 1000000007;long rem 1, x 3;f…

【PHP+代码审计】PHP基础——数据类型

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

012集——显示高考天数倒计时——vba实现

以下代码实现高考倒计时&#xff1a; Sub 高考倒计时() 高考日期 CDate("06,07," & Year(Date)) If Date > 高考日期 Then高考日期 CDate("06-07-" & Year(Date) 1) End If 年月日 Year(Date) & "年" & Month(Date) &am…