当前位置: 首页 > news >正文

C# 11 中的新增功能

我们很高兴地宣布 C# 11 已经发布!与往常一样,C# 开辟了一些全新的领域,同时推进了过去版本中一直在运行的几个主题。我们的文档页面上的 C# 11 的新增功能下有许多功能和详细信息,这些内容都得到了很好的介绍。

随着每个版本的发布,社区的参与度越来越高,他们贡献了从建议、见解和 bug 报告一直到整个功能实现的所有内容。这真的是每个人的C#。谢谢!

UTF-8字符串文字

默认情况下,C# 字符串被硬编码为 UTF-16,而互联网上流行的字符串编码是 UTF-8。为了最大限度地减少转换的麻烦和性能开销,您现在只需将 u8 后缀附加到字符串文字即可立即将它们转换为 UTF-8:

var u8 = "This is a UTF-8 string!"u8;
UTF-8 字符串文字简单地返回一个字节块——以 ReadOnlySpan<byte> 的形式。对于 UTF-8 编码很重要的场景,这可能比某些专用的新 UTF-8 字符串类型更有用。
  • 阅读有关 UTF-8 字符串文字的文档

原始字符串文字

字符串文字中的很多内容都是某种“代码”——不仅是程序文本,还有 JSON 和 XML 数据、HTML、正则表达式、SQL 查询等。当有许多特殊字符在 C# 字符串文字中具有特殊含义时,问题就会显现!值得注意的例子包括 \ 和 ",它们由 { 和 } 连接到内插字符串中。

为什么不采用一种完全没有转义字符的字符串文字形式呢?这就是原始字符串文字。

原始字符串文字至少由三个双引号分隔:

var raw1 = """This\is\all "content"!""";
Console.WriteLine(raw1);

This prints:

This\is\all "content"!

如果您需要三个或更多的“作为内容的一部分,您只需在外部使用更多的”。开头和结尾必须匹配:

var raw2 = """""I can do ", "", """ or even """" double quotes!""""";

这使得粘贴、维护和阅读文字包含的内容变得非常容易。

多行原始字符串文字也可以截断前导空格:结束引号的位置决定了输出中开始包含空格的位置:

var raw3 = """
    <element attr="content">
      <body>
        This line is indented by 4 spaces.
      </body>
    </element>
    """;
//  ^white space left of here is removed

由于右引号左侧有四个空格,因此从每行内容的开头删除四个空格,导致以下输出:

<element attr="content">
  <body>
    This line is indented by 4 spaces.
  </body>
</element>

原始字符串文字远不止于此——例如,它们支持字符串内插! 

  • 在文档中阅读有关原始字符串文字的更多信息

对静态成员进行抽象

你如何抽象出本质上是静态的操作——比如运算符?传统的答案是“poorly”。在 C# 11 中,我们发布了对接口中静态虚拟成员的支持,这在 C# 10 中处于预览状态。有了它,您现在可以定义一个非常简单的数学接口:

public interface IMonoid<TSelf> where TSelf : IMonoid<TSelf>
{
    public static abstract TSelf operator +(TSelf a, TSelf b);
    public static abstract TSelf Zero { get; }
}

请注意接口如何为“self”获取类型参数。那是因为静态成员没有 this。

现在任何人都可以通过为两个静态成员提供实现并将它们自己作为 TSelf 类型参数传递来实现此接口:

public struct MyInt : IMonoid<MyInt>
{
    int value;
    public MyInt(int i) => value = i;
    public static MyInt operator +(MyInt a, MyInt b) => new MyInt(a.value + b.value);
    public static MyInt Zero => new MyInt(0);
}

重要的是,您如何使用这些抽象操作?当没有实例可以调用它们时,您如何调用虚拟成员?答案是通过泛型。这是它的样子:

T AddAll<T>(params T[] elements) where T : IMonoid<T>
{
    T result = T.Zero;
    foreach (var element in elements)
    {
        result += element;
    }
    return result;
}

类型参数 T 受 IMonoid<T> 接口约束,这允许在 T 本身上调用该接口的静态虚拟成员——Zero 和 +!

现在我们可以用一些 MyInts 调用泛型方法,并通过类型参数传入+ 和 Zero 的正确实现:

MyInt sum = AddAll<MyInt>(new MyInt(3), new MyInt(4), new MyInt(5));

事实上,.NET 7 附带了一个新的命名空间 System.Numerics,其中充满了数学接口,表示您可能想要使用的运算符和其他静态成员的不同组合:IMonoid<T> 的“成熟”版本 接口如上。.NET 中的所有数字类型现在都实现了这些新接口——您也可以将它们添加到您自己的类型中!因此,现在很容易一劳永逸地编写数值算法——从它们处理的具体类型中抽象出来——而不是让大量的重载包含本质上相同的代码。

还值得注意的是,静态虚拟成员对于数学以外的其他事情也很有用。例如,您可以对类型层次结构的工厂方法进行抽象。但我们现在已经涵盖了足够多的内容——您可能想查看文档中关于静态抽象接口方法和泛型数学的这些教程。

即使您不使用静态虚拟成员创建接口,您也可以从现在和将来对 .NET 库所做的改进中受益。

列表模式

模式匹配是 C# 中正在进行的故事之一,我们只是不断地填充它。模式匹配是在 C# 7 中引入的,从那时起它已经发展成为该语言中最重要和最强大的控制结构之一。

C# 11 将列表模式添加到故事中。使用列表模式,您可以递归地将模式应用于类似列表的输入的单个元素——或者它们的范围。让我们直接进入上面的通用算法,使用列表模式重写为递归方法:

T AddAll<T>(params T[] elements) where T : IMonoid<T> =>
    elements switch
{
    [] => T.Zero,
    [var first, ..var rest] => first + AddAll<T>(rest),
};

里面进行了很多事情,但在中心是一个带有两种情况的 switch 表达式。一种情况为空列表 [] 返回零,其中 Zero 由接口定义。另一种情况使用 var first 模式将第一个元素提取到 first 中,然后使用 .. 将剩余元素提取到 rest 中,以将所有剩余元素切出到 var rest 模式中。

  • 在文档中阅读有关列表模式的更多信息。

必需的成员

我们一直致力于多个版本的另一个持续主题是改进对象创建和初始化。C# 11 继续对必需的成员进行这些改进。

在创建使用对象初始值设定项的类型时,您过去无法指定必须初始化某些属性。现在,您可以说属性或字段是必需的。这意味着当创建该类型的对象时,它必须由对象初始值设定项初始化:

public class Person
{
public required string FirstName { get; init; }
public string? MiddleName { get; init; }
public required string LastName { get; init; }
}

现在在没有初始化两个必需属性的情况下创建一个 Person 是错误的:

var person = new Person { FirstName = "Ada" }; // Error: no LastName!
  • 查看文档以获取有关所需成员的更多信息

写在最后

C# 11 还包括许多其他功能。我希望这道“开胃菜”能激发您探索 C# 11 中的新功能,并希望您在使用 C# 11 进行编码时获得与我们编写它时一样多的乐趣!我们努力使语言变得更有用,不仅通过增加更多的表达能力(如静态虚拟成员),而且通过简化、精简和删除样板(如原始字符串文字和列表模式)并使其更安全(如与必需的成员)。

了解 C#11更多新增功能~

相关文章:

  • 【蓝桥杯国赛真题06】python绘制菱形圆环 蓝桥杯青少年组python编程 蓝桥杯国赛真题解析
  • 我为什么选择博客园!
  • BUG系列路径规划算法原理介绍(六)——BugFlood算法
  • 毕设选题推荐基于python的django框架的自媒体社推广平台系统
  • LaTex入门(二):LaTex控制序列的作用
  • [Linux](16)网络编程:网络概述,网络基本原理,套接字,UDP,TCP,并发服务器编程,守护(精灵)进程
  • UI自动化总结
  • Zabbix6.0使用教程 (二)—zabbix6.0常用术语
  • java计算机毕业设计网络游戏管理网站源程序+mysql+系统+lw文档+远程调试
  • 【机器学习】Rasa NLU以及Rasa Core概念和语法简介(超详细必看)
  • Service (一) 启动/绑定服务
  • 数据结构-八大排序
  • MySQL小知识:为何从8.0开始取消了MySQL查询缓存
  • python数据类型(1)
  • HTML+CSS网页设计期末课程大作业 【茶叶文化网站设计题材】web前端开发技术 web课程设计 网页规划与设计
  • 4个实用的微服务测试策略
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • Java|序列化异常StreamCorruptedException的解决方法
  • Java-详解HashMap
  • Joomla 2.x, 3.x useful code cheatsheet
  • jquery ajax学习笔记
  • JSDuck 与 AngularJS 融合技巧
  • Laravel核心解读--Facades
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • SQLServer之创建数据库快照
  • vue 个人积累(使用工具,组件)
  • Vue官网教程学习过程中值得记录的一些事情
  • 百度小程序遇到的问题
  • 给github项目添加CI badge
  • 前端路由实现-history
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 数据结构java版之冒泡排序及优化
  • 算法-插入排序
  • 我建了一个叫Hello World的项目
  • 我看到的前端
  • 一份游戏开发学习路线
  • nb
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $ git push -u origin master 推送到远程库出错
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (SpringBoot)第七章:SpringBoot日志文件
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (原創) 物件導向與老子思想 (OO)
  • ***利用Ms05002溢出找“肉鸡
  • .bat文件调用java类的main方法
  • .net core 微服务_.NET Core 3.0中用 Code-First 方式创建 gRPC 服务与客户端
  • .NET DevOps 接入指南 | 1. GitLab 安装
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题