C# 14 包含以下新功能。 可以使用最新的 Visual Studio 2022 版本或 .NET 10 SDK 试用这些功能:
- 扩展成员
- 空条件赋值
-
nameof
支持未绑定泛型类型 -
为
Span<T>
和ReadOnlySpan<T>
提供更多隐式转换 - 简单 lambda 参数上的修饰符
-
field
支持的属性 -
partial
事件和构造函数
.NET 10 支持 C# 14。 有关详细信息,请参阅 C# 语言版本控制。
可以从 .NET 下载页下载最新的 .NET 10 SDK。 还可以下载 Visual Studio 2022,其中包括 .NET 10 SDK。
新功能一旦在公开预览版中发布,就会被添加到“C# 新特性”页中。 roslyn 功能状态页的工作集部分跟踪即将推出的功能何时合并到主分支中。 本文最后更新于 .NET 10 预览 1。
可以在我们的文章《重要更改》中查找 C# 14 中引入的任何 重大更改。
注释
我们对这些功能的反馈感兴趣。 如果发现上述任何新功能的问题,请在 dotnet/roslyn 存储库中创建一个新问题。
扩展成员
C# 14 添加了用于定义 扩展成员的新语法。 借助新语法,除了扩展方法之外,还可以声明 扩展属性 。 还可以声明扩展类型的扩展成员,而不是类型的实例。 换句话说,这些新的扩展成员可以作为扩展类型的静态成员出现。 下面的代码示例演示了可以声明的不同类型的扩展成员的示例:
public static class Enumerable
{
// Extension block
extension<TSource>(IEnumerable<TSource> source) // extension members for IEnumerable<TSource>
{
// Extension property:
public bool IsEmpty => !source.Any();
// Extension indexer:
public TSource this[int index] => source.Skip(index).First();
// Extension method:
public IEnumerable<TSource> Where(Func<TSource, bool> predicate) { ... }
}
// extension block, with a receiver type only
extension<TSource>(IEnumerable<TSource>) // static extension members for IEnumerable<Source>
{
// static extension method:
public static IEnumerable<TSource> Combine(IEnumerable<TSource> first, IEnumerable<TSource> second) { ... }
// static extension property:
public static IEnumerable<TSource> Identity => Enumerable.Empty<TSource>();
}
}
第一个扩展块中的成员被调用时,就好像它们是IEnumerable<TSource>
的实例成员,例如sequence.IsEmpty
。 第二个扩展块中的成员被调用时,如同它们是IEnumerable<TSource>
的静态成员,例如IEnumerable<int>.Identity
。
可以通过阅读有关编程指南中的扩展成员的文章、有关关键字的语言参考文章extension
以及新扩展成员功能的功能规范来了解更多详细信息。
field
关键字
使用令牌 field
可以编写属性访问器体,而无需声明后备字段。 令牌 field
将替换为编译器合成支持字段。
例如,以前,如果要确保 string
属性无法设置为 null
,则必须声明一个后备字段并实现这两个访问器:
private string _msg;
public string Message
{
get => _msg;
set => _msg = value ?? throw new ArgumentNullException(nameof(value));
}
现在可以简化代码,以便:
public string Message
{
get;
set => field = value ?? throw new ArgumentNullException(nameof(value));
}
可以为字段支持的属性的一个或两个访问器声明一个主体。
如果类型中还包含一个名为 field
的符号,则在读取代码时可能会出现重大更改或混淆。 可以使用 @field
或 this.field
消除关键字和标识符之间的 field
歧义,也可以重命名当前 field
符号以提供更好的区别。
如果尝试此功能并收到反馈,请对存储库中的csharplang
发表评论。
field
上下文关键字在 C# 13 中作为预览特性提供。
隐式跨度转换
C# 14 在语言中引入了对 System.Span<T> 和 System.ReadOnlySpan<T> 的一流支持。 此支持涉及新的隐式转换,允许对这些类型进行更自然的编程。
在 C# 和运行时中,Span<T>
和 ReadOnlySpan<T>
被用于多种关键方式。 他们的引入可提高性能,而不会造成安全风险。 C# 14 识别其相互关系,并支持在 ReadOnlySpan<T>
、Span<T>
和 T[]
之间进行一些转换。 跨度类型可以作为扩展方法的接收器、与其他转换组合,或者在泛型类型推理场景中提供帮助。
可以在语言参考部分的 内置类型 的文章中找到隐式跨度转换的列表。 可以通过阅读 First 类跨度类型的功能规范来了解更多详细信息。
未绑定泛型类型和 nameof
从 C# 14 开始,nameof
的参数可以是未绑定的泛型类型。 例如,nameof(List<>)
计算为 List
。 在早期版本的 C# 中,只能使用关闭的泛型类型(例如 List<int>
)返回 List
名称。
带修饰符的简单 lambda 参数
可以在不指定参数类型的情况下,向 lambda 表达式参数添加参数修饰符,例如scoped
、ref
、in
、out
或 ref readonly
。
delegate bool TryParse<T>(string text, out T result);
// ...
TryParse<int> parse1 = (text, out result) => Int32.TryParse(text, out result);
以前,仅当参数声明包含参数的类型时,才允许添加任何修饰符。 上述声明需要所有参数的类型:
TryParse<int> parse2 = (string text, out int result) => Int32.TryParse(text, out result);
修饰符 params
仍然需要显式输入的参数列表。
可以在有关 C# 语言参考中 lambda 表达式 的文章中详细了解这些更改。
更多部分成员
部分构造函数和分部事件必须包含一个 定义声明 和一个 实现声明。
只有部分构造函数的实现声明可以包含构造函数初始值设定项: this()
或 base()
。 只有一个分部类型声明可以包含主构造函数语法。
部分事件的实现声明必须包含 add
和 remove
访问器。 定义声明申明了一个类似字段的事件。
Null 条件分配
null 条件成员访问运算符 ?.
和 ?[]
现在可以被放在赋值或复合赋值表达式的左边。
在 C# 14 之前,在分配给属性之前,需要对变量进行 null 检查:
if (customer is not null)
{
customer.Order = GetCurrentOrder();
}
可以使用运算符简化上述代码 ?.
:
customer?.Order = GetCurrentOrder();
运算符 =
的右侧仅在左侧不为 null 时才会被计算。 如果 customer
为 null,则代码不调用 GetCurrentOrder
。
除了赋值之外,还可以将 null 条件成员访问运算符与复合赋值运算符(+=
-=
和其他)一起使用。 但是,不允许递增 ++
和递减 --
。
可以在语言参考文章中详细了解 条件成员访问 和 null 条件分配的功能规范。