摘要:今天大姚带领大家一起来看看 C# 13 中的新增几大功能,并了解其功能特性和实际应用场景。
今天大姚带领大家一起来看看 C# 13 中的新增几大功能,并了解其功能特性和实际应用场景。
要体验 C# 13 新增的功能可以使用最新的 Visual Studio 2022 版本或 .NET 9 SDK 尝试这些功能。
Visual Studio 2022安装C# 13 中的 params 集合变得类型更灵活,满足更复杂的应用场景,并且性能得到了进一步的提升。
在 C# 13 之前:params 仅支持一维数组(如params int list、params object list)。调用方法时需显式传递数组或数组元素类型的参数的逗号分隔列表。在 C# 13 中:params 修饰符并不局限于数组类型。 现在可以将 params 用于任何已识别的集合类型,包括
System.Span、System.ReadOnlySpan,以及那些实现System.Collections.Generic.IEnumerable并具有 Add 方法的类型。 除了具体类型外,还可以使用接口System.Collections.Generic.IEnumerable、System.Collections.Generic.IReadOnlyCollection、System.Collections.Generic.IReadOnlyList、System.Collections.Generic.ICollection和 System.Collections.Generic.IList。 public static void SpanDataPrintRun{
Span originalSpan = [1, 2, 3, 4, 5];
SpanDataPrint(originalSpan);
}
public static void SpanDataPrint(params Span spans)
{
for(int i = 0; i < spans.Length; i++)
{
Console.WriteLine(spans[i]);
}
}
.NET 9 包含一种新的用于互斥的System.Threading.Lock类型,比仅在任意System.Object实例上进行锁定更有效。该类型通过其 API 提供更好的线程同步,通过Lock.EnterScope返回的ref struct自动管理锁的释放,减少死锁风险。
System.Threading.Lock类型提案:https://github.com/dotnet/runtime/issues/34812
private System.Threading.Lock _newLock = new System.Threading.Lock;
public voidLockTest
{
lock (_oldLock)
{
Console.WriteLine("Old lock");
}
lock (_newLock)
{
// 传统 lock 语法(优化版)
}
using (_newLock.EnterScope)
{
// 作用域自动释放(推荐写法)
}
_newLock.Enter;
try
{
// 显式 Enter/Exit 调用
}
finally { _newLock.Exit; }
if(_newLock.TryEnter)
{
try
{
// 非阻塞尝试获取锁
}
}
}
新增\eESCAPE字符Unicode U+001B的字符文本转义序列。以前,只能使用的是\u001b或\x1b。不建议使用\x1b,因为如果1b后面的下一个字符是有效的十六进制数字,则那些字符会成为转义序列的一部分。 public static void NewEscapeSequence
{
Console.WriteLine("[31m红色文本[0m");
// C# 13 之前
Console.WriteLine("\u001b[31m红色文本\u001b[0m"); //输出红色文字
// C# 13 中
Console.WriteLine("\e[31m红色文本\e[0m");//功能相同,语法更简洁
}
此功能对涉及方法组的重载解析进行了少量优化。方法组是一个方法,并且所有重载都具有相同的名称。 编译器以前的行为是为方法组构造完整的候选方法集。如果需要自然类型,则自然类型是根据整套候选方法确定的。
详细介绍:https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/proposals/csharp-13.0/method-group-natural-type-improvements
// C# 13 中可以直接使用方法组并推断自然类型:var a = Example.Method; // 成功推断为Action(选择第一个匹配的委托类型)
// 通过上下文进一步优化推断:
List> actions =new { Example.Method }; // 根据集合类型推断为Action
在C# 13中允许在对象初始化表达式中使用运算符(从末尾索引)直接为集合元素赋值。 public class numbers
{
public int Datas { get;set; } = new int[8];
}
public static voidImplicitIndexAccess
{
var countdown = newNumbers
{
Datas =
{
[1] = 0,
[2] = 1,
// 从 C# 13 开始可以执行下面方式赋值
[^3] = 2,
[^4] = 3,
[^5] = 4
}
};
}
在 C# 13 之前,迭代器方法(使用yield return的方法)和async方法不能声明局部unsafe在 C# 13 中,方法可以声明ref局部变量或ref struct类型的局部变量。 但不可跨await或使用。同样,C# 13 允许在迭代器方法中使用unsafe上下文。但是,所有yield return和yield break语句都必须在安全的上下文中。
应用场景:提升内存敏感操作(如高性能 Span 处理)的灵活性。
在 C# 13 之前,ref struct类型不能声明为泛型或方法的类型参数。现在,泛型类型声明可以添加反约束allows ref struct。 此反约束声明为该类型参数提供的类型参数可以是ref struct类型。编译器会对该类型参数的所有实例执行ref安全规则。应用场景:适用于游戏引擎、实时数据处理等需要低延迟内存操作的领域。通过泛型约束,可编写同时支持 ref struct和非ref struct的通用代码。
例如,可以像下面的代码一样声明一个泛型类型:
public class C whereT : allows ref struct{
// 使用 T 作为 ref struct:
public void M(scoped T p)
{
//参数 p 必须遵循 ref 安全规则
}
}
allows ref struct 反约束声明相应的类型参数可以是 ref struct 类型。 该类型参数的实例必须遵循以下规则:
它不能被装箱。
它参与引用安全规则。
不能在不允许 ref struct 类型的地方使用实例,例如 static 字段。
实例可以使用 scoped 修饰符进行标记。
现如今可以在 C# 13 中声明partial属性和partial索引器。partial属性和索引器通常遵循与partial方法相同的规则:创建一个定义声明,一个实现声明。这两种声明的签名必须匹配。一个限制是,不能使用自动属性声明来实现部分属性。未声明正文的属性被视为声明声明。注意:不允许对构造函数、终结器、重载运算符或事件声明使用 partial 关键字。在 C# 13 之前,不允许对属性或索引器使用partial。
public partial class MyClass{
public partial string Name { get;set; }
}
{
private string _name;
public partial string Name
{
get => _name;
set=> _name = value;
}
}
在 C# 13 中,编译器识别
OverloadResolutionPriorityAttribute,以便优先选择一个重载而不是另一个。库作者可以使用该属性确保新的、更好的重载比现有的重载更受青睐。应用场景:适用于解决特定场景下的重载冲突和性能优化需求。通过合理设置优先级,开发者可以在保持代码兼容性的同时,优化编译器的选择逻辑。
public class Printer{
[OverloadResolutionPriority(1)] //优先调用
public static void PrintWay(params int numberList) { }
public static void PrintWay(params ReadOnlySpan numberList) { }
}
来源:opendotnet