c# 12 新特性有哪些

来源:这里教程网 时间:2026-02-21 17:38:06 作者:

C# 12 已于 2023 年 11 月正式发布,当前(2025 年底)已在 .NET 8+ 生产环境广泛落地。它不是“语法糖堆砌”,而是围绕减少样板代码、提升集合操作表达力、强化性能控制三个核心目标设计的实用升级。

主构造函数:类/结构体声明即初始化

你不再需要写

private readonly string _name;
+ 显式构造函数 + 属性赋值三行代码。主构造函数把参数直接“注入”到类型作用域中:

public class Person(string name, int age)
{
    public string Name => name;  // name 可直接用,无需字段声明
    public int Age => age;
    public void Introduce() => Console.WriteLine($"I'm {Name}, {Age} years old.");
}
适用于
class
struct
record
,不限于记录类型
参数自动成为私有只读捕获字段(编译器生成),不可在外部修改 ⚠️ 常见坑:不能在字段初始值设定项中直接引用主构造参数(如
private string _fullName = $"{name}";
会报错),必须改用属性或构造函数体
record
深度协同:结合
record class Person(string name, int age);
可一行定义不可变数据容器 + 相等性 +
ToString()

集合表达式:
[]
统一初始化所有集合

告别

new int[] {1, 2, 3}
new List<string> {"a", "b"}</string>
Enumerable.Range(1, 5).ToList()
等不一致写法。C# 12 用统一
[]
语法覆盖数组、列表、栈、自定义集合(只要实现
IEnumerable<t></t>
且有合适构造函数):

int[] arr = [1, 2, 3];
List<string> list = ["hello", "world"];
var range = [.. Enumerable.Range(10, 3)]; // [10, 11, 12]
var combined = [.. arr, .. list.Select(s => s.Length), 999]; // 混合展开
..
是展开操作符(spread),可展开任意
IEnumerable<t></t>
,不只是数组
编译器按目标类型选择最优构造方式:目标是
int[]
就生成数组;目标是
List<t></t>
就调用
List<t>(IEnumerable<t>)</t></t>
构造函数
⚠️ 常见坑:若目标类型无匹配构造函数或工厂方法(如某些第三方集合),会编译失败;此时需显式构造或加转换 性能友好:比链式
.ToList().AddRange()
更少中间分配

默认 lambda 参数:让匿名函数真正可复用

以前写带默认行为的 lambda,得靠

??
或条件判断;现在可像普通方法一样定义默认值:

var log = (string msg, LogLevel level = LogLevel.Information) =>
    Console.WriteLine($"[{level}] {msg}");
<p>log("Started");                    // [Information] Started
log("Failed", LogLevel.Error);     // [Error] Failed
默认值必须是编译时常量(
1
"default"
typeof(T)
等),不能是运行时变量
支持命名参数调用(如
log(msg: "x", level: LogLevel.Warning)
⚠️ 常见坑:lambda 类型推导可能失败——若未显式标注委托类型(如
Action<string loglevel></string>
),编译器有时无法识别含默认参数的 lambda,建议在复杂场景显式声明委托变量
特别适合事件回调、配置钩子、测试模拟等需要“可选定制”的场景

InlineArray:高性能固定大小缓冲区的终极方案

当你要在 struct 中存几个 float、int 或 byte(比如音频采样点、游戏顶点坐标),又不想触发 GC 或内存碎片?

[InlineArray]
让你把数组“内联”进结构体布局:

[System.Runtime.CompilerServices.InlineArray(1024)]
public struct AudioBuffer
{
    private float _element0; // 编译器自动扩展为 1024 个 float 字段
}
<p>// 使用时像普通数组
var buf = new AudioBuffer();
buf[0] = 0.1f;
buf[1023] = -0.5f;
完全栈分配(若 struct 在栈上),零 GC 压力,缓存友好
List<float></float>
快 10 倍以上(实测),比
Span<float></float>
更轻量(无长度/指针管理开销)
⚠️ 常见坑:大小必须是编译期常量;不支持泛型参数化尺寸;仅限
struct
;调试器显示可能不直观(显示为字段列表而非数组)
典型场景:Unity DOTS 中的 Job 数据块、实时音频处理 buffer、高频小数据包序列化

C# 12 的真实价值不在“炫技”,而在于它把过去要靠经验、模板、甚至第三方库才能写得又快又稳的模式,变成了语言原生支持的几行代码。但要注意:这些特性依赖 .NET 8 SDK(或更高版本)和 C# 12 语言版本设置(项目文件中需有

<langversion>12</langversion>
),旧项目迁移时容易漏掉这个配置,导致编译器静默降级到 C# 11 行为。

相关推荐