Is there an “Empty List” singleton in C#?
在C中,我很好地使用LINQ和IEnumerable。一切都很好(至少大部分是这样)。
然而,在许多情况下,我发现自己需要一个空的IEnumerable作为默认值。也就是说,我想
1
| for (var x in xs) { ... } |
不需要空检查就可以工作。这就是我目前所做的,取决于更大的背景:
1 2
| var xs = f () ?? new X [0]; // when xs is assigned, sometimes
for (var x in xs ?? new X [0]) { ... } // inline, sometimes |
现在,虽然上面的内容对我来说非常好——也就是说,如果在创建数组对象时有任何"额外开销",我只是不在乎——我想知道:
C/.NET中是否存在"Empty Immutable IEnumerable/IList"单例?(即使没有,是否有更好的方法来处理上述情况?)
Java具有EDCOX1,1,不可变的单体——"EDCX1",通过EDCOX1,2,-这是为了这个目的,虽然我不确定一个类似的概念是否能在C**中工作,因为泛型的处理方式不同。
谢谢。
- 好吧,该死的:)这就是我关注list/ilist而不是Enumerable/i enumerable的原因,谢谢大家——投票无处不在。
- stackoverflow.com/questions/3229698/…
- public static class Array { public static readonly T[] Empty = new T[0]; },可以称为:Array.Empty。我在代码审查中问过这个问题。
你在找Enumerable.Empty();。
在其他新闻中,Java空列表很糟糕,因为列表接口公开了将元素添加到抛出异常的列表中的方法。
- 这是非常正确的观点!也许它需要一个新的问题?
- 您的速度慢了几秒钟,没有文档链接*finger shake*;-),但接受了对svicks评论的扩展。
- 另外,其他人得到了更多的赞成票,所以我们是平等的:)我会发布一个问题,但我现在就要睡觉了,我将无法跟踪这个问题。为什么不自己贴呢?
- 因为自从你指出这一点后,这似乎很明显=^^=
- 因为类方法可能需要返回List(可以通过索引访问的集合)。那些List可以是只读的。有时您需要返回这样一个只读的List,其中包含零元素。因此,Collections.emptyList()方法。不能只返回空的ITerable,因为实现的接口指定该方法返回一个列表。最大的问题是它们不是可以返回的不可变列表接口。在.NET中也存在同样的问题:任何IList都可能是只读的。
- 另一方面,每个数组在C中都是一个ilist,当您试图添加新项时,这也会抛出。
- 函数shouldiuseList(readOnlyMethoded)返回(setOfListMethods()-setOfInterableMethods())。包含(readOnlyMethoded);
- 抛出异常vs只读接口~=运行时出错vs编译时出错。我肯定会更喜欢Java规范来为列表定义一个只读接口,但不幸的是情况并非如此。
- 它可能关注的对象:通常,想要某种清单(而不是IEnumerable)的原因是它被物化(没有延迟执行)和拥有一个已知的Count。在这种情况下,我们应该使用IReadOnlyCollection。如果还需要索引访问,则存在IReadOnlyList。
Enumerable.Empty()正是这样。
- 嗯,不完全是。:)由于需要"列表",所以Array.Empty()更准确,因为它是IList。同时也满足了IReadOnlyCollection的快乐利益。当然,当一个IEnumerable足够时,Enumerable.Empty()完全适合。
- @东帝汶这个问题,以及包括这个问题在内的许多答案,都是在江户十一〔五〕年前写的。:)在任何情况下,尽管标题如此,但问题明确表明,IEnumerable是有利于实现这一目的的。
我想你在找Enumerable.Empty()。
空列表单例没有那么多意义,因为列表通常是可变的。
我认为添加一个扩展方法是一个干净的选择,因为它们能够处理空值,比如:
1 2 3 4 5 6 7 8 9
| public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list)
{
return list ?? Enumerable.Empty<T>();
}
foreach(var x in xs.EmptyIfNull())
{
...
} |
在原始示例中,使用空数组提供空的可枚举数组。虽然使用Enumerable.Empty()是完全正确的,但也可能存在其他情况:如果必须使用数组(或IList接口),则可以使用该方法
这有助于避免不必要的分配。
注释/参考:
- 文档没有提到这个方法只为每种类型分配一次空数组。
- Roslyn分析器建议使用警告CA1825的方法:避免零长度数组分配
- Microsoft参考实现
- .NET核心实现
使用带列表的Enumerable.Empty()有一个缺点。如果将Enumerable.Empty交给列表构造函数,则会分配一个大小为4的数组。但是,如果将一个空的Collection交给列表构造函数,那么就不会发生分配。因此,如果在代码中使用此解决方案,那么很可能会使用IEnumerable中的一个来构建列表,从而导致不必要的分配。
Microsoft实现了类似于此的"any()"(源代码)
1 2 3 4 5 6 7 8 9
| 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()的扩展方法,只需重写并进行以下三项更改:
1 2 3 4 5 6 7 8 9
| 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
} |