Is there an “Empty List” singleton in C#?

扶醉桌前 提交于 2019-12-03 05:23:34

问题


In C# I use LINQ and IEnumerable a good bit. 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. 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? (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.

Thanks.


回答1:


You are looking for Enumerable.Empty<int>();

In other news the Java empty list sucks because the List interface exposes methods for adding elements to the list which throw exceptions.




回答2:


Enumerable.Empty<T>() is exactly that.




回答3:


I think you're looking for Enumerable.Empty<T>().

Empty list singleton doesn't make that much sense, because lists are often mutable.




回答4:


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())
  {
    ...
  }



回答5:


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

System.Array.Empty<T>()

which helps you to avoid unnecessary allocations.

Notes / References:

  • the documentation does not mention that this method allocates the empty array only once for each type
  • roslyn analyzers recommend this method with the warning CA1825: Avoid zero-length array allocations
  • Microsoft reference implementation
  • .NET Core implementation



回答6:


Microsoft implemented `Any()' like this (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;
}

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:

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
}



回答7:


Using Enumerable.Empty<T>() with lists has a drawback. If you hand Enumerable.Empty<T> into the list constructor then an array of size 4 is allocated. But if you hand an empty Collection into the list constructor then no allocation occurs. So if you use this solution throughout your code then most likely one of the IEnumerables will be used to construct a list, resulting in unnecessary allocations.



来源:https://stackoverflow.com/questions/8555865/is-there-an-empty-list-singleton-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!