简体   繁体   English

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

[英]Is there an "Empty List" singleton in C#?

In C# I use LINQ and IEnumerable a good bit.在 C# 中,我很好地使用了 LINQ 和 IEnumerable。 And all is well-and-good (or at least mostly so).一切都很好(或至少大部分是这样)。

However, in many cases I find myself that I need an empty IEnumerable<X> as a default.但是,在许多情况下,我发现自己需要一个空的IEnumerable<X>作为默认值。 That is, I would like也就是说,我想

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

to work without needing a null-check.无需空检查即可工作。 Now this is what I currently do, depending upon the larger context:现在这就是我目前所做的,这取决于更大的背景:

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

Now, while the above is perfectly fine for me -- that is, if there is any "extra overhead" with creating the array object I just don't care -- I was wondering:现在,虽然以上对我来说完全没问题——也就是说,如果创建数组对象有任何“额外开销”,我只是不在乎——我想知道:

Is there "empty immutable IEnumerable/IList" singleton in C#/.NET? C#/.NET 中是否有“空的不可变 IEnumerable/IList”单例? (And, even if not, is there a "better" way to handle the case described above?) (而且,即使没有,是否有“更好”的方法来处理上述情况?)

Java has Collections.EMPTY_LIST immutable singleton -- "well-typed" via Collections.emptyList<T>() -- which serves this purpose, although I am not sure if a similar concept could even work in C# because generics are handled differently. Java 有Collections.EMPTY_LIST不可变单例——通过Collections.emptyList<T>() “类型良好”——它用于这个目的,尽管我不确定类似的概念是否可以在 C# 中工作,因为泛型的处理方式不同。

Thanks.谢谢。

You are looking for Enumerable.Empty<T>() .您正在寻找Enumerable.Empty<T>()

In other news the Java empty list sucks because the List interface exposes methods for adding elements to the list which throw exceptions.在其他新闻中,Java 空列表很糟糕,因为 List 接口公开了将元素添加到列表中的方法,这些方法会引发异常。

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

I think you're looking for Enumerable.Empty<T>() .我认为您正在寻找Enumerable.Empty<T>()

Empty list singleton doesn't make that much sense, because lists are often mutable.空列表单例没有多大意义,因为列表通常是可变的。

In your original example you use an empty array to provide an empty enumerable.在您的原始示例中,您使用一个空数组来提供一个空的枚举。 While using Enumerable.Empty<T>() is perfectly right, there might other cases: if you have to use an array (or the IList<T> interface), you can use the method虽然使用Enumerable.Empty<T>()是完全正确的,但可能还有其他情况:如果必须使用数组(或IList<T>接口),则可以使用该方法

System.Array.Empty<T>()

which helps you to avoid unnecessary allocations.这可以帮助您避免不必要的分配。

Notes / References:注释/参考文献:

I think adding an extension method is a clean alternative thanks to their ability to handle nulls - something like:我认为添加扩展方法是一种干净的替代方法,因为它们能够处理空值——例如:

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

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

Microsoft implemented `Any()' like this ( source )微软像这样实现了“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;
}

If you want to save a call on the call stack, instead of writing an extension method that calls !Any() , just rewrite make these three changes:如果要在调用堆栈上保存调用,而不是编写调用!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
}

Using Enumerable.Empty<T>() with lists has a drawback.对列表使用Enumerable.Empty<T>()有一个缺点。 If you hand Enumerable.Empty<T> into the list constructor then an array of size 4 is allocated.如果您将Enumerable.Empty<T>传递到列表构造函数中,则会分配一个大小为 4 的数组。 But if you hand an empty Collection into the list constructor then no allocation occurs.但是,如果您将一个空的Collection交给列表构造函数,则不会发生分配。 So if you use this solution throughout your code then most likely one of the IEnumerable s will be used to construct a list, resulting in unnecessary allocations.因此,如果您在整个代码中使用此解决方案,则很可能会使用IEnumerable之一来构建列表,从而导致不必要的分配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM