Collection Expressions 是 C# 12 引入的集合初始化语法糖,用统一的 [...] 字面量替代 new T[] { }、new List { } 等冗长写法,编译器依左侧类型自动调用构造函数或 Create 方法,支持数组、List、Span 等,不支持 HashSet、Dictionary 等非线性结构。

Collection Expressions 是什么,和以前写法有什么区别
C# 12 的 collection expressions 不是新类型或新类,而是一种语法糖,让初始化集合更简洁、更统一。它覆盖了数组、List<t></t>、Span<t></t>、ReadOnlySpan<t></t> 等多种目标类型,底层仍调用对应类型的构造或工厂方法。
以前你要写:
var arr = new[] { 1, 2, 3 };
var list = new List<int> { 4, 5, 6 };
var span = stackalloc int[] { 7, 8, 9 };现在可以统一写成:
int[] arr = [1, 2, 3]; List<int> list = [4, 5, 6]; Span<int> span = [7, 8, 9];
关键点:方括号 [] 是新的字面量语法,编译器根据左侧变量类型自动推导目标集合形式;不是所有类型都支持——必须有匹配的构造函数、静态 Create 方法,或实现 ICollection<t></t> 并有无参构造。
哪些类型能直接用 [] 初始化
支持开箱即用的类型包括:
-
T[](数组) List<t></t>-
ImmutableArray<t></t>(需引用System.Collections.Immutable) -
Span<t></t>和ReadOnlySpan<t></t>(仅限栈分配,且必须在unsafe上下文或局部函数中) - 自定义类型只要满足:有
public T(params T[] items)构造函数,或public static T Create(ReadOnlySpan<t> items)</t>静态方法
不支持的常见情况:
-
HashSet<t></t>(无对应构造/工厂签名,默认不支持) -
Dictionary<k v></k>(键值对结构不匹配线性元素列表) -
IEnumerable<t></t>接口本身(无法实例化)
嵌套、拼接与泛型推导的实际写法
collection expressions 支持展开其他集合(用 ..),也支持混合字面量与变量:
var a = [1, 2]; var b = [3, 4]; var combined = [..a, 5, ..b]; // 结果是 [1, 2, 5, 3, 4]
泛型推导规则简单粗暴:以第一个元素类型为基准,后续元素必须可隐式转换:
var mixed = [1, 2.0, 3L]; // ❌ 编译错误:类型不一致 var ints = [1, 2, 3]; // ✅ 推导为 int[]
注意:.. 展开只接受实现了 IEnumerable<t></t> 或有 Length/Count 属性 + 索引器的类型;Span<t></t> 可展开,但 IEnumerable<t></t> 不能直接展开进 Span<t></t>(生命周期不匹配)。
常见报错和绕过方式
遇到 CS8991: Collection expression cannot be converted to type 'X',通常是因为:
- 目标类型没提供兼容的构造函数或
Create方法 - 使用了不支持的类型(如
HashSet<int></int>),此时得退回到传统写法:new HashSet<int> { 1, 2, 3 }</int> - 在非局部作用域(比如字段初始化)用了
Span<t></t>字面量(栈内存不能逃逸),改用int[]或Memory<int></int>
另外,collection expressions 不支持带逻辑的初始化(比如条件项、循环生成),这类需求仍得靠 LINQ 或手动构建。
真正容易被忽略的是:编译器对 .. 展开的求值时机——它在运行时逐个复制元素,不是引用传递;如果源集合很大或含副作用(比如 IEnumerable 是延迟执行的查询),要注意性能和行为变化。


















