C# 15 包含以下新功能。 使用最新的 Visual Studio 2026 内部预览版或 .NET 11 预览版 SDK 试用这些功能:
C# 15 是最新的 C# 预览版。 .NET 11 预览版支持 C# 15。 有关详细信息,请参阅 C# 语言版本控制。
可以从 .NET 下载页下载最新的 .NET 11 预览版 SDK。 还可以下载 Visual Studio 2026 内部预览版,其中包括 .NET 11 预览版 SDK。
“C# 中的新增功能”页面在公共预览版中可用时会添加新功能。 roslyn 功能状态页的工作集部分跟踪即将推出的功能何时合并到主分支中。
您可以在我们关于重大变更的文章中找到 C# 15 中引入的任何重大变更。
注释
我们对这些功能的反馈感兴趣。 如果发现上述任何新功能的问题,请在 dotnet/roslyn 存储库中创建一个新问题。
集合表达式参数
可以用 with(...) 元素作为集合表达式的第一个元素,将参数传递给底层集合的构造函数或工厂方法。 借助此功能,可以直接在集合表达式语法中指定容量、比较器或其他构造函数参数。
以下示例演示如何将容量参数传递给List<T>构造函数,以及传递比较器给HashSet<T>:
string[] values = ["one", "two", "three"];
// Pass capacity argument to List<T> constructor
List<string> names = [with(capacity: values.Length * 2), .. values];
// Pass comparer argument to HashSet<T> constructor
HashSet<string> set = [with(StringComparer.OrdinalIgnoreCase), "Hello", "HELLO", "hello"];
// set contains only one element because all strings are equal with OrdinalIgnoreCase
若要了解有关集合表达式参数的详细信息,请参阅有关集合表达式或特征规范的语言参考文章。 有关在集合初始值设定项中使用集合表达式参数的信息,请参阅 对象和集合初始值设定项。
联合类型
C# 15 引入了 联合类型,这些类型表示可以是多种 事例类型之一的值。 使用 union 关键字声明联合:
public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);
public union Pet(Cat, Dog, Bird);
联合提供了从每种用例类型的隐式转换,并且编译器确保 switch 表达式在所有案例类型上是穷尽的:
Pet pet = new Dog("Rex");
string name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
运行时包括从 .NET 11 预览版 5 开始的 UnionAttribute 和 IUnion 类型。
建议规范中的某些功能尚未实现。 这些功能将在未来预览版中推出。
封闭层次结构
从 C# 15 开始,可以将修饰符应用于 closed 类来声明 封闭层次结构。 封闭类只能在其声明程序集内被派生,这会在编译时固定直接后代的集合:
public closed record class GateState;
public record class Closed : GateState;
public record class Open(float Percent) : GateState;
由于编译器知道每个直接后代,因此 switch 处理每个子代的表达式是详尽的,不需要默认 arm:
string Describe(GateState state) => state switch
{
Closed => "closed",
Open(var percent) => $"{percent}% open",
// No warning: every direct descendant of 'GateState' is handled.
};
closed 修饰符是上下文关键字。
closed 类是隐式 abstract 的,不能与 sealed、static 或显式 abstract 修饰符结合使用。 派生不是传递性的:封闭类的非封闭后代仍然可以在其他程序集中被派生。 为了将穷举性检查扩展到层次结构下游,也要将中间后代标记为 closed。
注释
在 C# 15 预览版 5 中,运行时尚未附带 System.Runtime.CompilerServices.ClosedAttribute。 在完成之前,使用 closed 修饰符的每个项目都必须声明属性本身:
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public sealed class ClosedAttribute : Attribute { }
有关详细信息,请参阅语言参考中的 封闭修饰符 和 封闭层次结构模式 ,或 功能规范。 你可以从 ClosedAttribute GitHub 存储库中的 keywords 片段项目复制本节中的示例,包括 dotnet/docs 解决方法。
内存安全
C# 15 开启了一项跨多个版本重新定义该语言内存安全性的工作。 目标是将 unsafe 上下文与实际访问非托管内存的操作关联起来,而不是与指针类型的存在关联起来。 大多数内存安全漏洞都来自这些访问操作,因此该语言使审阅者和审核员脱颖而出。
在完整的模型中,成员上的 unsafe 将其标记为 requires-unsafe:审核责任转移至调用方,调用方必须在 unsafe 上下文中使用该成员。 程序集选择加入此强制,编译器使用 System.Runtime.CompilerServices.MemorySafetyRulesAttribute 属性记录选择。 该模型还添加了一个 safe 上下文关键字,用于将 extern 成员和显式布局字段标记为安全。 这些规则共同使潜在的内存不安全性边界跨程序明确。
第一步包括指针放松。 使用 preview 语言版本进行编译时,以下操作不再需要 unsafe 上下文:
- 声明指针类型并使用运算符获取变量
&的地址。 -
fixed语句,用于锁定变量。 - 将
stackalloc表达式转换为指针。 - 应用于任何非托管类型的
sizeof运算符。
以下示例创建并固定没有上下文的 unsafe 指针:
int number = 42;
int* pointer = &number;
int[] numbers = [10, 20, 30];
fixed (int* first = numbers)
{
// Dereferencing the pointer still requires an unsafe context.
}
访问指向内存的操作(如指针间接访问(*p)、指针成员访问(p->member)、指针元素访问(p[i])和函数指针调用仍需要 unsafe 上下文。
requires-unsafe 成员模型、程序集对更新后的内存安全规则的自愿采用,以及 safe 上下文关键字将在后续预览版中推出。
有关详细信息,请参阅语言引用或功能规范中的不安全代码、指针类型和函数指针。