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
将被用来构造一个列表,导致不必要的分配。