c# 12 新特性有哪些

16次阅读

C# 12 是围绕减少样板代码、提升集合操作表达力、强化性能控制三大目标设计的实用升级,包含主构造函数、集合表达式、默认Lambda参数和InlineArray四大核心特性。

c# 12 新特性有哪些

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."); }
  • 适用于 classStructrecord,不限于记录类型
  • 参数自动成为私有只读捕获字段(编译器生成),不可在外部修改
  • ⚠️ 常见坑:不能在字段初始值设定项中直接引用主构造参数(如 private string _fullName = $"{name}"; 会报错),必须改用属性或构造函数体
  • record 深度协同:结合 record class Person(string name, int age); 可一行定义不可变数据容器 + 相等性 + ToString()

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

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

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

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

以前写带默认行为的 lambda,得靠 ?? 或条件判断;现在可像普通方法一样定义默认值:

var log = (string msg, LogLevel level = LogLevel.Information) =>     Console.WriteLine($"[{level}] {msg}"); 

log("Started"); // [Information] Started log("Failed", LogLevel.Error); // [Error] Failed

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

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

当你要在 struct 中存几个 Float、int 或 byte(比如音频采样点、游戏顶点坐标),又不想触发 GC 或内存碎片?[InlineArray] 让你把数组“内联”进结构体布局:

[System.Runtime.CompilerServices.InlineArray(1024)] public struct AudioBuffer {     private float _element0; // 编译器自动扩展为 1024 个 float 字段 } 

// 使用时像普通数组 var buf = new AudioBuffer(); buf[0] = 0.1f; buf[1023] = -0.5f;

  • 完全分配(若 struct 在栈上),零 GC 压力,缓存友好
  • List 快 10 倍以上(实测),比 Span 更轻量(无长度/指针管理开销)
  • ⚠️ 常见坑:大小必须是编译期常量;不支持泛型参数化尺寸;仅限 struct;调试器显示可能不直观(显示为字段列表而非数组)
  • 典型场景:unity DOTS 中的 Job 数据块、实时音频处理 buffer、高频小数据包序列化

C# 12 的真实价值不在“炫技”,而在于它把过去要靠经验、模板、甚至第三方库才能写得又快又稳的模式,变成了语言原生支持的几行代码。但要注意:这些特性依赖 .NET 8 SDK(或更高版本)和 C# 12 语言版本设置(项目文件中需有 12),旧项目迁移时容易漏掉这个配置,导致编译器静默降级到 C# 11 行为。

text=ZqhQzanResources