C# 13 新功能预览:探索最新预览特性

Avatar
不若风吹尘
2024-07-16T18:26:36
214
0

C# 13 正逐步成型,其特性聚焦于灵活性、性能以及让日常使用的功能更加出色。在今年的 Microsoft Build 大会上,展示了 C# 13 即将迎来的一些变化。今天,我想分享 C# 13 中当前可尝试的功能状态,并提供关于此版本及未来规划的特性更新。让我们详细看看这些新特性吧。

如何立即体验 C# 13

在深入了解 C# 13 的每个新特性之前,你可能想知道如何尝试它们。你可以在.NET 9 预览版(撰写时为 Preview 6)和 Visual Studio 2022-17.11 的最新预览版中找到 C# 13 的最新预览。要访问预览特性,请在项目文件中将语言版本设置为 preview

<LangVersion>preview</LangVersion>

params集合

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

params 关键字出现在参数前,调用该方法时可以提供零个或多个值的逗号分隔列表。以下示例在所有版本的 C# 中都有效:

public void WriteNames(params string[] names) => Console.WriteLine(string.Join(", ", names));
WriteNames("Mads", "Dustin", "Kathleen");
WriteNames(new[] { "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));

重载解析

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

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 时提供警告。

索引器从末尾初始化

索引运算符 ^ 允许你相对于集合末尾来指示集合中的位置。这现在在初始化器中也可用。

class Program {
    static void Main() {
        var x = new Numbers {
            Values = { [1] = 111, [^1] = 999 } // C# 13起有效
        };
        // x.Values[1] 是 111
        // x.Values[9] 是 999,因为它是最后一个元素
    }
}

转义序列 \e

C# 13 引入了一个新的转义序列,用于表示你所知的 ESCAPEESC 字符。之前必须将其键入为 \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");

部分属性

C# 13 新增了部分属性(partial properties)。和部分方法一样,它们的主要目的是支持源生成器。部分方法已存在多版本,并在 C# 9 中进行了额外改进。部分属性与它们的部分方法类似。

方法组自然类型改进

自然类型是指编译器确定的表达式类型,比如当类型被赋给 varDelegate 时。如果是简单类型,这很简单。C# 10 中添加了对方法组的支持。当作为委托包含不带括号的方法名时,会使用方法组:

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

C# 13 细化了确定自然类型的规则,以便按作用域考虑候选者,并修剪没有成功机会的候选者。更新这些规则意味着在处理方法组时更少的编译器错误。

允许 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;
// 正确
Span<int> local = Identity(new Span<int>(new int[10]));

async 方法和迭代器中使用 refunsafe

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

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

同样,C# 13 允许在迭代器方法中使用 unsafe 上下文。然而,所有 yield returnawait 语句必须处于安全上下文中。这些放宽的限制使你能在更多地方使用 ref 局部变量和 ref struct 类型。

扩展类型更新

在.NET Build 公告博客文章中描述了扩展类型。当时,目标是让该功能的关键部分在 C# 13 中实现,但设计和实施需要更多时间。请期待在 C# 14(.NET 10)的早期预览中看到扩展类型。

总结

你可以在 [C# 13 新特性概览] 中找到更多关于这些特性的信息。你可以在 Roslyn 特性状态页面查看进展。同时,请务必关注.NET 9 预览版发行说明,你可以在那里找到每个发行版的 C# 发行说明。

Last Modification : 9/19/2024 9:20:03 PM


In This Document