list不支持直接列表模式匹配,因编译器要求类型具备span兼容性,而list索引器非ref-returning;需用toarray()(有gc压力)、asspan()(推荐,零分配)或改用readonlymemory/span。

List[...] 语法List<t></t> 虽然有这两者,但编译器在模式匹配中默认不视为可切片序列——这是最容易踩的坑。
为什么 list is [1, 2, 3] 编译失败?
错误现象:CS8121 “无法将类型 ‘ListList<t></t> 的索引器访问不是 ref-returning,也不满足 Span 构造要求。
可行方案只有三种:
- 显式调用
ToArray():if (list.ToArray() is [1, 2, 3]) { ... }—— 但每次触发堆分配,高频调用会放大 GC 压力 - 用
AsSpan()(推荐):if (list.AsSpan() is [1, 2, 3]) { ... }—— 零分配,安全,前提是 .NET 6+ 且 list 不为空(空 list 的AsSpan()返回空 span,能正常匹配[]) - 改用
ReadOnlyMemory<t></t>或Span<t></t>作为输入源,从源头避免 List
[..] 切片模式在 List 上怎么写才不报错?
切片模式(如 [1, .., 5] 或 [.., 3])对 List<t></t> 同样不直接可用。你不能写 list is [1, ..],但可以:
- 用
AsSpan()+ 切片:if (list.AsSpan() is [1, ..])—— 匹配首元素为 1 的任意长度非空序列 - 捕获中间段:
if (list.AsSpan() is [.., 2, 3, ..var middle])—— 注意:左侧..和右侧..不能同时出现,否则编译报错CS8901 - 想匹配“倒数第二个是 4”?写成:
if (list.Count >= 2 && list[^2] == 4)更直白,也比AsSpan()+ 模式更易读
匹配嵌套结构时,List 模式和属性模式怎么配合?
列表模式可嵌套在属性模式里,但目标对象必须是“可索引 + 可数”的类型,List<t></t> 在这里依然要先转:
比如有个类 Response { public List<int> Data { get; } = new(); }</int>,你想匹配 Data 是 [10, 20, ..]:
var resp = new Response { Data = new() { 10, 20, 30 } };
if (resp is { Data: var data } && data.AsSpan() is [10, 20, ..])
{
Console.WriteLine("前两个是 10 和 20");
}
不能简写成 resp is { Data: [10, 20, ..] },因为 Data 是 List<int></int>,不是编译器认可的列表模式载体。
真正要注意的复杂点在于:列表模式不是语法糖,它会生成边界检查和索引访问代码;一旦用了 AsSpan(),就得确保 list 没被其他线程修改(Span 是 ref-like 类型,无线程安全保证)。日常开发中,简单长度/首尾判断用 .Count 和 [0]、[^1] 更稳;只有在多条件组合、需解构多个位置值时,才值得上 AsSpan() + 列表模式。










