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

问题描述 投票:0回答:7

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

但是,在很多情况下,我发现自己需要一个空的

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

现在,虽然上面的内容对我来说非常好——也就是说,如果创建数组对象有任何“额外的开销”,我只是不在乎——我想知道:

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

Java 有

Collections.EMPTY_LIST
不可变的单例——通过
Collections.emptyList<T>()
“类型正确”——它可以达到这个目的,尽管我不确定类似的概念是否可以在 C# 中工作,因为泛型的处理方式不同。

谢谢。

c# singleton ienumerable empty-list
7个回答
118
投票

您正在寻找

Enumerable.Empty<T>()

在其他新闻中,Java 空列表很糟糕,因为 List 接口公开了向列表添加元素的方法,这些方法会引发异常。


57
投票

Enumerable.Empty<T>()
正是如此。


25
投票

在原始示例中,您使用空数组来提供空枚举。虽然使用

Enumerable.Empty<T>()
是完全正确的,但可能还有其他情况:如果您 必须使用 数组(或
IList<T>
接口),则可以使用该方法

System.Array.Empty<T>()

这可以帮助您避免不必要的分配。

注释/参考文献:


20
投票

我认为您正在寻找

Enumerable.Empty<T>()

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


11
投票

我认为添加扩展方法是一个干净的替代方案,因为它们能够处理空值 - 例如:

  public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list)
  {
    return list ?? Enumerable.Empty<T>();
  }

  foreach(var x in xs.EmptyIfNull())
  {
    ...
  }

2
投票

Enumerable.Empty<T>()
与列表一起使用有一个缺点。如果将
Enumerable.Empty<T>
交给列表构造函数,则会分配一个大小为 4 的数组。但是,如果您将空的
Collection
传递给列表构造函数,则不会发生分配。因此,如果您在整个代码中使用此解决方案,那么很可能会使用其中一个
IEnumerable
来构造列表,从而导致不必要的分配。


1
投票

微软像这样实现了 `Any()' (source)

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
}
© www.soinside.com 2019 - 2024. All rights reserved.