collection表达式类型由左侧声明决定,不依赖方括号内元素;如var x = [1,2,3]推导为int[],list需显式声明;不支持隐式转换、跨assembly需c# 12+。

Collection表达式不是万能类型推导器,必须看左侧声明类型
编译器不靠方括号里的内容猜类型,而是严格按变量或参数的声明类型来决定怎么构造。写 var x = [1, 2, 3]; 推出的是 int[],不是 List<int></int>;想得到 List<int></int>,必须显式写 List<int> x = [1, 2, 3];</int>。
常见错误现象:List<int> y = [1, 2, 3];</int> 编译失败,报错类似 无法将“集合表达式”隐式转换为 List<int></int>。
-
IEnumerable<int> e = [1, 2, 3];</int>✅ 因为int[]实现了该接口 -
Span<int> s = [1, 2, 3];</int>✅ 但仅限局部变量或unsafe上下文(栈分配语义) -
HashSet<int> h = [1, 2, 3];</int>❌ 默认不支持,无匹配构造函数或Create方法 -
Dictionary<string int> d = ["a", 1];</string>❌ 键值对结构不匹配线性列表
展开运算符 .. 只能在 [] 内部用,且右侧必须是可枚举的
.. 不是解构,也不是参数展开,它只在集合表达式内部合法。写在方法调用里(比如 SomeMethod(..list))直接语法错误。
正确用法示例:var combined = [1, 2, ..existingList, 5];
- 右侧必须实现
IEnumerable<t></t>,或有Length/Count+ 索引器(如Span<t></t>) -
IEnumerable<int></int>可以展开进int[]或List<int></int>,但不能直接展开进Span<int></int>(生命周期不匹配) - 嵌套展开不支持:
[..[..inner]]❌;但[..a, ..b]✅ - 不能展开
object或未泛型集合(如ArrayList)
泛型推导以第一个元素为准,混合类型会编译失败
集合表达式不做隐式升格或统一类型转换。写 [1, 2.0, 3L] 会立刻编译报错,因为 int、double、long 三者没有公共隐式转换目标。
实际开发中容易忽略这点,尤其在拼接常量与变量时:
-
var nums = [1, 2, 3];→ 推导为int[] -
var mixed = [1, (short)2, 3];❌ 编译失败(short不能隐式转int) - 安全做法:显式转成同一类型,如
[(long)1, 2L, 3L]或用变量统一声明 - 字符串字面量和
string变量混用没问题,因都满足string类型
不能用于常量、默认参数或属性初始化器中的字段赋值
集合表达式不是编译时常量,所以不能出现在需要常量的地方。
-
const int[] C = [1, 2, 3];❌ 报错:常量必须是编译时常量 -
void M(int[] data = [1, 2, 3]) { }❌ 方法参数默认值不支持集合表达式 -
private readonly int[] _data = [1, 2, 3];✅ 字段初始化允许(非常量) -
public IEnumerable<int> Data => [1, 2, 3];</int>✅ 表达式体属性允许
最易被忽略的是跨 assembly 引用场景:即使你用了 ImmutableArray<t></t> 并加了引用,若对方项目没启用对应语言版本(C# 12+),这个 [...] 语法仍会编译失败——它依赖编译器层面支持,不是运行时库特性。











