技术速递|C# 13:探索最新的预览功能

作者:Kathleen Dollard
排版:Alan Wang

C# 13 已初具雏形,其新特性侧重于灵活性、性能以及使您最喜欢的功能在日常中变得更容易使用。我们以公开的方式构建 C#,在今年的 Microsoft Build 大会上,我们会让您一睹 C# 13 的精彩之处。今天,我们想分享一下 C# 13 当前的状态,以及您今天就可以尝试的新功能,并提供有关此版本及以后计划中的功能更新。让我们更详细地了解这些新功能。

  • 增强了 params 集合以实现更强的灵活性
  • lock 对象
  • 索引运算符改进
  • 转义序列 \e
  • Partial 属性
  • 方法组自然类型改进
  • Async 方法和迭代器中的 ref 和 unsafe
  • 扩展类型更新

立即试用 C# 13

在我们深入研究 C# 13 的每个新功能之前,您可能想知道如何使用它。

您可以在最新的 .NET 9 预览版(撰写本文时为预览版 6)和 Visual Studio 2022-17.11 的最新预览版中找到 C# 13 的最新预览版。若要访问预览功能,请在项目文件中将您的语言版本设置为 preview:

<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><!--其他设置--><LangVersion>preview</LangVersion><!--其他设置--></PropertyGroup>
</Project>

Params 集合

C# 13扩展了 params 关键字,使其适用于可以通过集合表达式构造的任何类型。无论是编写方法还是调用方法,都增加了灵活性。

当 params 关键字出现在参数之前时,对该方法的调用可以提供零个或多个值的逗号分隔列表。以下内容适用于所有版本的 C#:

public void WriteNames(params string[] names)=> Console.WriteLine(String.Join(", ", names));
WriteNames("Mads", "Dustin", "Kathleen");
WriteNames(new string[] {"Mads", "Dustin", "Kathleen"});
// 这两个都会输出:Mads、Dustin、Kathleen

请注意,您可以使用逗号分隔的值列表或基础类型的对象来调用该方法。

从 C# 13 开始,params 参数可以是集合表达式支持的任何类型。例如:

public void WriteNames(params List<string> names)=> Console.WriteLine(String.Join(", ", names));

每当调用具有 IEnumerable 参数的方法时,都可以传递 LINQ 表达式的结果。如果 IEnumerable 参数具有 params 修饰符,还可以传递逗号分隔列表。当有常量,可以使用逗号分隔列表;当您需要 LINQ 表达式时,您可以使用它:

public void WriteNames(params IEnumerable<string> names)=> Console.WriteLine(String.Join(", ", names));
var persons = new List<Person>
{new Person("Mads", "Torgersen"),new Person("Dustin", "Campbell"),new Person("Kathleen", "Dollard")
};
//以下所有输出:Mads、Dustin、Kathleen
WriteNames("Mads", "Dustin", "Kathleen");
WriteNames(persons.Select(person => person.FirstName));
WriteNames(from p in persons select p.FirstName);

重载解析

编写方法时,可以提供多个 params 重载。例如,添加 IEnumerable 重载可支持 LINQ,添加 ReadOnlySpan 或 Span 重载可减少分配,从而可以提高性能。

public void WriteNames(params string[] names)=> Console.WriteLine(String.Join(", ", names));
public void WriteNames(params ReadOnlySpan<string> names)=> Console.WriteLine(String.Join(", ", names));
public void WriteNames(params IEnumerable<string> names)=> Console.WriteLine(String.Join(", ", names));

当传递指定类型之一时,将使用该重载。当传递逗号分隔值或不传递任何值时,将选择最佳重载。使用上述重载:

// 使用 IEnumerable 重载
WriteNames(persons.Select(person => person.FirstName)); 
// 使用数组重载
WriteNames(new string[] {"Mads", "Dustin", "Kathleen"}); 
// 使用最有效的过载:当前为 ReadOnlySpan
WriteNames("Mads", "Dustin", "Kathleen");    

多重重载可以增加便利性并提高性能。库作者应该为所有重载提供相同的语义,这样调用者就不需要关心使用了哪个重载。

Lock 对象

.NET 9 包含一种新的用于互斥的 System.Threading.Lock 类型,比仅在任意 System.Object 实例上进行锁定更有效。System.Threading.Lock 类型提案详细介绍了该类型及其创建原因。随着时间的推移,该类型有望成为 C# 代码中大多数锁定的主要机制。

C# 13 使该类型的使用变得简单。当编译器识别出 lock 语句的目标是 System.Threading.Lock 对象时,C# 就会生成对 System.Threading.Lock API 的调用,并在 Lock 实例可能被错误地视为普通 object 的情况下提供警告。

此更新意味着 lock 语句的熟悉语法利用了运行时中的新功能。熟悉的代码只需进行少量更改即可变得更好。只需将项目的 TargetFramework 更改为 .NET 9,并将 lock 的类型从 object 更改为 System.Threading.Lock:

public class MyClass 
{private object myLock = new object();public void MyMethod() {lock (myLock){// 您的代码}          }
}
public class MyClass 
{// 以下行是唯一的变化private System.Threading.Lock myLock = new System.Threading.Lock();public void MyMethod() {lock (myLock){// 您的代码}     }
}

从初始化器末尾开始的索引

索引运算符 ^ 允许您在可计数集合中相对于集合末尾指定一个位置。这现在适用于初始化器:

class Program
{ static void Main(){var x = new Numbers{Values = {[1] = 111,[^1] = 999  // 从 C# 13 开始的工作}// x.Values[1] 为 111// x.Values[9] 为 999,因为它是最后一个元素};}
}
class Numbers
{public int[] Values { get; set; } = new int[10];
}

转义序列 \e

C# 13 为众所熟知的 ESCAPE 或 ESC 字符引入了新的转义序列。以前您必须将其输入为 \u001b 的变体。当使用 VT100/ANSI 转义码与 System.Console 的终端交互时,此新序列特别方便。例如:

// C# 13 之前版本
Console.WriteLine("\u001b[1mThis is a bold text\u001b[0m");
// 使用 C# 13
Console.WriteLine("\e[1mThis is a bold text\e[0m");

这使得创建精美的终端输出变得更容易并且更不容易出错。

Partial 属性

C# 13 添加了 partial 属性。与 partial 方法一样,它们的主要目的是支持源生成器。Partial 方法已在许多版本中可用,并在 C# 9 中进行了额外的改进。Partial 属性与它们的 partial 方法非常相似。

例如,从 .NET 7(C# 12)开始,正则表达式源生成器为方法创建高效的代码:

[GeneratedRegex("abc|def")]
private static partial Regex AbcOrDefMethod();
if (AbcOrDefMethod().IsMatch(text))
{// 使用匹配的文本采取行动
}

在 .NET 9(C# 13)中,Regex 源生成器已更新,如果您更喜欢使用属性,您也可以使用:

[GeneratedRegex("abc|def")]
private static partial Regex AbcOrDefProperty { get; };
if (AbcOrDefProperty.IsMatch(text))
{// 使用匹配的文本采取行动
}

Partial 属性将使源生成器设计人员更容易创建自然感觉的 API。

方法组自然类型改进

表达式的自然类型是由编译器确定的类型,例如当类型分配给 var 或 Delegate 时。当它是一个简单类型时,这很简单。在 C# 10 中,我们添加了对方法组的支持。当您将不带括号的方法名称作为委托包含时,将使用方法组:

Todo GetTodo() => new(Id: 0, Name: "Name");
var f = GetTodo; // f 的类型是 Func<ToDo>

C# 13 完善了确定自然类型的规则,以便根据范围考虑候选者并删除没有成功机会的候选者。更新这些规则意味着在使用方法组时编译器错误会更少。

allows ref struct

C# 13 添加了一种指定泛型类型参数功能的新方法。默认情况下,类型参数不能为 ref struct。但是 C# 13 允许您指定类型参数可以是 ref struct,并应用相应的规则。虽然其他泛型约束限制了可用作类型参数的类型集,但此新规范扩展了允许的类型。我们认为这是一种反约束,因为它删除了限制,而不是添加了限制。where 子句中的语法 allows ref struct,其中 allows 表示用法上的扩展:

T Identity<T>(T p)where T : allows ref struct=> p;
// Okay
Span<int> local = Identity(new Span<int>(new int[10]));

使用 allows ref struct 指定的类型参数具有 ref struct 类型的所有行为和限制。

Async 方法和迭代器中的 ref 和 unsafe

在 C# 13 之前,迭代器方法(使用 Yield Return 的方法)和 async 方法不能声明局部 ref 变量,也不能具有 unsafe 的上下文。

在 C# 13 中,async 方法可以声明 ref 局部变量,或 ref struct 类型的局部变量。这些变量不能跨 await 边界或 Yield return 边界保存。

同样,C# 13 允许迭代器方法中使用 unsafe 上下文。但是,所有 Yield Return 和 Await 语句都必须在safe上下文中。这些放宽的限制让您可以在更多地方使用 ref 局部变量和 ref struct类型。

扩展类型的更新

我们对 Mads 和 Dustin 在 Build 上展示的扩展类型功能感到非常兴奋。我们还在 Build 上的博客文章 .NET 公告中介绍了扩展类型。当时,我们的目标是在 C# 13中实现该功能的关键部分,但设计和实现将需要更多的时间。请在早期的 C# 14(NET 10)预览版中查找扩展类型。

总结

您可以在 C# 13 的新增功能中了解更多相关内容。我们仍在为 C# 13 开发新功能,您可以在 Roslyn 功能状态页面查看我们正在做的事情。此外,请务必关注 .NET 9 预览版发行说明,您现在可以在其中找到每个版本的 C# 发行说明。

请下载带有 .NET 9 的 Visual Studio 2022-17.11 的最新预览版,体验这些新功能,并告诉我们您的想法!

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

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

相关文章

基于vite + pnpm monorepo 实现一个UI组件库

基于vite pnpm monorepo的vue组件库 仓库地址 思路 好多文章都是直接咔咔咔的上代码。跟着做也没问题&#xff0c;但总觉得少了些什么。下次做的时候还要找文章参考。。 需求有三个模块&#xff0c;那么就需要三个包。使用monorepo进行分包管理。 a. 组件库 b. 组件库文档…

Linux C语言 54-目录操作

Linux C语言 54-目录操作 本节关键字&#xff1a;Linux、C语言、目录操作、遍历目录 相关C库函数&#xff1a;opendir、readdir、closedir 遍历目录 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <dirent.h> #include <…

如何在Linux上部署Django Web应用

在Linux上部署Django Web应用需要遵循以下步骤&#xff1a; 安装Python和虚拟环境&#xff1a; 首先&#xff0c;确保你的Linux系统已经安装了Python。可以使用以下命令检查Python版本&#xff1a; python --version如果没有安装Python&#xff0c;则可以使用包管理工具安装它&…

Java:114-Spring Boot的底层原理(上篇)

Spring Boot的底层原理 之前学习过了Spring Boot&#xff08;在88章博客&#xff09;&#xff0c;但是并没有很深入的了解&#xff0c;这里致力于在原来的基础上学习更多Spring Boot知识 回顾&#xff08;注意&#xff1a;只是回顾&#xff0c;所以更多细节在88章博客&#x…

MySQL零散拾遗(五)---- 对 GROUP BY 要点进行详细介绍

在GROUP BY的使用过程中&#xff0c;SELECT 中出现的非组函数的字段必须声明在 GROUP BY 中。 还记得 MySQL零散拾遗&#xff08;四&#xff09; 中&#xff0c;提到的 GROUP BY 的使用要点嘛&#xff1f; SELECT 中出现的非组函数的字段必须声明在 GROUP BY 中。反而&#x…

array.some() ==> 查找数组list中,是否有包含与当前currKey的值不一样的misId

需求&#xff1a; const list [ {misId: e, name: 小白}, {misId: e, name: 小白白}, {misId: r, name: 小王}, {misId: r, name: 小小王} ] let currKey r 查找数组list中&#xff0c;是否有包含与当前currKey的值不一样的misId 解决&#xff1a; 要查找数组lis…

【2】Spring Cloud 工程搭建

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Spring Cloud实战&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1.声明项目依赖和项目构建插件 2.完善子项目订单服务 2.1完善启动…

开源发票识别InvoiceNet项目Windows部署踩坑记(1)

今天安装在github上的InvoiceNet开源项目&#xff0c;准备对它进行测试&#xff0c;安装过程出现了一些问题&#xff0c;做个记录&#xff0c;给遇到兄弟爬坑。 第一个问题&#xff0c;conda的问题&#xff0c; 这是另外一个包管理器&#xff0c;不仅仅可以管理python的虚拟…

layui+thymeleaf+jquery实现多图片,多视频的上传、预览、放大、编辑功能

layuithymeleafjquery实现多图片&#xff0c;多视频的上传、预览、放大、编辑功能 html: <!--多图片上传--> <div class"layui-row layui-col-space10"><div class"layui-form-item"><div class"layui-form-item layui-form-te…

mybatis xml 文件中引用Java类的静态方法

MyBatis-Plus 支持在 XML 映射文件中使用 ${} 来直接嵌入字符串&#xff0c;以及使用 #{} 来引用传入参数。但是&#xff0c;$ 的使用需要小心&#xff0c;因为它会直接将参数内容嵌入到 SQL 语句中&#xff0c;这可能会导致 SQL 注入问题。 在 MyBatis-Plus 中&#xff0c;如果…

Android 防止重复点击

1.第一种方式&#xff1a; private static final int MIN_DELAY_TIME 2000; // 两次点击间隔不能少于2000ms private static long lastClickTime System.currentTimeMillis(); public static boolean isFastClick() { boolean flag true; long currentClickTime …

苹果电脑怎么清理缓存和垃圾 mac如何关闭正在运行的程序 苹果电脑怎么清理后台

苹果电脑以其出色的性能和用户友好的界面而广受好评&#xff0c;但在使用过程中&#xff0c;后台程序的堆积可能会影响到系统的运行效率。太多应用和进程在后台默默运行&#xff0c;就像是无形的背包&#xff0c;让你的Mac背负了太多不必要的重量。不过&#xff0c;别担心&…

08、Tomcat 部署及优化

8.1 Tomcat概述 8.1.1 Tomcat介绍 自从 JSP 发布之后,推出了各式各样的 JSP 引擎。Apache Group 在完成 GNUJSP1.0的开发以后&#xff0c;开始考虑在 SUN 的 JSWDK 基础上开发一个可以直接提供 Web 服务的 JSP服务器&#xff0c;当然同时也支持 Servlet, 这样 Tomcat 就诞生…

使用LSTM完成时间序列预测

c 在本教程中&#xff0c;我们将介绍一个简单的示例&#xff0c;旨在帮助初学者入门时间序列预测和 PyTorch 的使用。通过这个示例&#xff0c;你可以学习如何使用 LSTMCell 单元来处理时间序列数据。 我们将使用两个 LSTMCell 单元来学习从不同相位开始的正弦波信号。模型在…

Perl 哈希

Perl 哈希 Perl 哈希是一种强大的数据结构&#xff0c;用于存储键值对集合。它是 Perl 语言的核心特性之一&#xff0c;广泛应用于各种编程任务中。本文将详细介绍 Perl 哈希的概念、用法和最佳实践。 什么是 Perl 哈希&#xff1f; Perl 哈希是一种关联数组&#xff0c;其中…

MYSQL 七、mysql 日志与备份

一、其他数据库日志 千万不要小看日志。很多看似奇怪的问题&#xff0c;答案往往就藏在日志里。很多情况下&#xff0c;只有通过查看日志才 能发现问题的原因&#xff0c;真正解决问题。所以&#xff0c;一定要学会查看日志&#xff0c;养成检查日志的习惯&#xff0c;对提升你…

C语言-预处理详解

1.预处理符号 C语言中设置了一些预定义符号&#xff0c;可以直接使用&#xff0c;预定义符号是在预处理期间处理的。 __FILE__//代表当前进行编译的源文件 __LINE__//文件当前行号 __DATE__//文件当前日期 __TIME__//文件当前时间 __STDC__//如果编译器遵循ANSIC&#xff0c;…

重复图片查找:巧用Python和OpenCV进行图像哈希与汉明距离检测以从海量图片中找出重复图片

重复图片查找&#xff1a;巧用Python和OpenCV进行图像哈希与汉明距离检测以从海量图片中找出重复图片 1. 导言2. 环境准备3. 图像哈希&#xff08;pHash&#xff09;原理4. 汉明距离原理5. 代码实现导入必要的库图像哈希计算函数汉明距离计算函数查找重复图片函数示例使用 在处…

【ELK+Kafka+filebeat分布式日志收集】kibana基本使用教程

基本功能 查询数据 在Discover中查看数据: 进入Discover视图。 选择之前创建的索引模式。 使用搜索框和过滤器来查询和过滤数据。 使用KQL(Kibana Query Language): KQL是一种简单的查询语法,用于过滤Elasticsearch中的数据。 支持Terms Query、Boolean Queries、Range …

分布式锁的实现:Redis和Zookeeper

在分布式系统中&#xff0c;确保数据的一致性和避免并发问题是非常重要的。分布式锁是解决这些问题的关键技术之一。本文将详细介绍如何使用Redis和Zookeeper实现分布式锁&#xff0c;并通过Java代码示例帮助读者理解其实现原理。 1. 分布式锁的基本概念 分布式锁是一种用于协…