用 enumerable.empty() 返回空集合更轻量、语义更清晰:它返回静态缓存的单例实例,零分配、零gc压力,且明确表达“空只读序列”意图;而 new list() 和 new t[0] 均会重复分配对象,且语义模糊。

直接说结论:用 Enumerable.Empty<t>()</t> 返回空集合,比 new List<t>()</t> 或 new T[0] 更轻量、更语义清晰,且能避免不必要的对象分配。
为什么不用 new List() 或 new T[0]?
很多人习惯写 return new List<string>();</string> 或 return new string[0];,但它们有隐含成本:
-
new List<t>()</t>每次都新建一个可变容器对象,哪怕它为空,也占内存、触发 GC 压力 -
new T[0]虽然数组不可变,但每次调用仍分配新数组对象(.NET 不会自动复用零长度数组) - 两者都不表达“我明确要一个空的、只读的、延迟兼容的序列”这层意图
Enumerable.Empty() 的实际行为和适用场景
Enumerable.Empty<t>()</t> 返回的是一个静态缓存的、类型安全的空 IEnumerable<t></t> 实例——内部是单例,不分配新对象,且实现了 ICollection<t></t> 和 IReadOnlyCollection<t></t>。
- 适合所有需要返回“空序列”的公开 API,比如过滤后无结果、配置未启用时的默认值
- 与 LINQ 链式调用天然兼容:
source.Where(...).Concat(Enumerable.Empty<int>())</int> - 在异步流(
IAsyncEnumerable<t></t>)中不适用,此时应改用AsyncEnumerable.Empty<t>()</t>(需System.Linq.Async包) - 不能直接当
List<t></t>用——它不支持Add、Count等方法(除非显式转型,但没必要)
常见误用和性能陷阱
看似简单,但容易踩坑:
- 写成
Enumerable.Empty(漏掉泛型参数)→ 编译错误:The non-generic type 'Enumerable' cannot be used with type arguments - 在循环里反复调用
Enumerable.Empty<int>()</int>→ 没问题,它是静态方法,返回同一实例,无性能损失 - 想用它初始化字段或属性时写成
private readonly IEnumerable<string> _empty = Enumerable.Empty<string>();</string></string>→ 完全正确,且推荐 - 误以为它等价于
null→ 它是非 null 的有效集合,foreach安全,.Any()返回false,.Count()返回0
最常被忽略的一点:如果你的函数签名返回的是 IList<t></t> 或 ICollection<t></t>,就不能直接返回 Enumerable.Empty<t>()</t>——它不实现这些接口(虽然 .NET 6+ 的 EmptyEnumerable<t></t> 内部已实现 IReadOnlyCollection<t></t>,但依然不是 ICollection<t></t>)。这时候要么改返回类型为 IEnumerable<t></t>,要么退而求其次用 Array.Empty<t>()</t>(它返回 T[],实现了全部集合接口,且也是静态缓存)。










