C#中有一个“空列表”单例吗?

在C#中我使用LINQ和IEnumerable很好。 一切都很好(或者至less大部分如此)。

但是,在很多情况下,我发现自己需要一个空的IEnumerable<X>作为默认值。 那就是,我想

 for (var x in xs) { ... } 

不需要空检查就可以工作。 现在这就是我目前所做的,取决于更大的背景:

 var xs = f() ?? new X[0]; // when xs is assigned, sometimes for (var x in xs ?? new X[0]) { ... } // inline, sometimes 

现在,虽然上述对我来说完全正确的 – 也就是说,如果创build数组对象有任何“额外的开销”,我只是不在乎 – 我想知道:

C#/。NET中是否存在“空不变的IEnumerable / IList”单例? (即使不是,有没有更好的办法来处理上述情况?)

Java具有Collections.EMPTY_LIST不可变单例 – 通过Collections.emptyList<T>() “well-typed” – 这是为此目的服务的,尽pipe我不确定类似的概念是否可以在C#中工作,因为generics的处理方式不同。

谢谢。

您正在寻找Enumerable.Empty<int>();

在其他消息中,Java空列表很糟糕,因为List接口暴露了向列表中添加元素的方法,这些元素会抛出exception。

Enumerable.Empty<T>()就是这样。

我想你正在寻找Enumerable.Empty<T>()

空列表单例没有太多意义,因为列表通常是可变的。

我认为增加一个扩展方法是一个干净的select,这要归功于它们处理空值的能力 – 例如:

  public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list) { return list ?? Enumerable.Empty<T>(); } foreach(var x in xs.EmptyIfNull()) { ... } 

微软实现了像这样( 源 )的Any()

 public static bool Any<TSource>(this IEnumerable<TSource> source) { if (source == null) throw new ArgumentNullException("source"); using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return true; } return false; } 

如果你想在调用堆栈上保存一个调用,而不是写一个调用!Any()的扩展方法,只需重写这三个改变:

 public static bool IsEmpty<TSource>(this IEnumerable<TSource> source) //first change (name) { if (source == null) throw new ArgumentNullException("source"); using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return false; //second change } return true; //third change } 

在列表中使用Enumerable.Empty<T>()有一个缺点。 如果您将Enumerable.Empty<T>移到列表构造函数中,则会分配一个大小为4的数组。 但是,如果您将一个空的Collection交给列表构造函数,则不会发生分配。 所以,如果你在你的代码中使用这个解决scheme,那么最有可能的一个IEnumerable将被用来构造一个列表,导致不必要的分配。