是否有“空名单”? C# 中的单例?

发布于 2024-12-21 20:23:36 字数 972 浏览 6 评论 0原文

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

但是,在许多情况下,我发现自己需要一个空的 IEnumerable 作为默认值。也就是说,我想

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# 中工作,因为泛型的处理方式不同。

谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

此岸叶落 2024-12-28 20:23:36

您正在寻找 Enumerable.Empty()

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

You are looking for 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.

不忘初心 2024-12-28 20:23:36

Enumerable.Empty()正是如此。

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

谎言月老 2024-12-28 20:23:36

在原始示例中,您使用空数组来提供空枚举。虽然使用 Enumerable.Empty() 是完全正确的,但可能还有其他情况:如果您必须使用数组(或 IList; 接口),您可以使用该方法

System.Array.Empty<T>()

来帮助您避免不必要的分配。

注释/参考:

In your original example, you use an empty array to provide an empty enumerable. While using Enumerable.Empty<T>() is perfectly right, there might be 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:

独享拥抱 2024-12-28 20:23:36

我认为您正在寻找 Enumerable。空()

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

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

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

旧街凉风 2024-12-28 20:23:36

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

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

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

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())
  {
    ...
  }
清君侧 2024-12-28 20:23:36

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

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.

梦中楼上月下 2024-12-28 20:23:36

Microsoft 像这样实现了“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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文