【问题标题】:Recommended way to check if a sequence is empty检查序列是否为空的推荐方法
【发布时间】:2011-01-06 20:58:46
【问题描述】:

一个方法返回一个序列IEnumerable<T>,你现在想检查它是否为空。你如何建议这样做?我正在寻找良好的可读性和良好的性能。

第一个也是最明显的方法是检查计数是否大于零:

if(sequence.Count() == 0)

具有不错的可读性,但性能很差,因为它实际上必须遍历整个序列。

我有时使用的一种方法如下:

if(!sequence.Any())

这并不(据我所知)必须遍历整个序列,但可读性有点倒退和尴尬。 (如果我们检查序列是否为 not 空的话会更好读)。

另一种选择是在 try-catch 中使用 First,如下所示:

try
{
    sequence.First();
}
catch(InvalidOperationException)
{
    // Do something
}

不是一个非常漂亮的解决方案,而且可能也更慢,因为它使用了异常和东西。当然可以通过使用FirstOrDefault 来防止这种情况发生,除非如果序列中的第一项实际上是默认值,你会遇到一个大问题;)

那么,还有其他方法可以检查序列是否为空吗?你通常使用哪一种?您推荐使用哪一种?

注意:为了获得最佳可读性,我可能会将上述 sn-ps 之一放在 IsEmpty 扩展方法中,但我仍然很好奇,因为我会在该方法中也做一些事情:p

【问题讨论】:

  • sequence 是什么类型?
  • @Beska:如果序列没有实现ICollection<T>,它只是迭代。请参阅文档:msdn.microsoft.com/en-us/library/bb338038.aspx
  • @Neil: IEnumerable。我想应该在某个地方注意到这一点。编辑:)

标签: c# linq ienumerable


【解决方案1】:

我个人会使用!sequence.Any()

如果您真的需要,您可以随时编写自己的扩展方法:

public static bool IsEmpty<T>(this IEnumerable<T> source)
{
    return !source.Any();
}

然后你可以写:

if (sequence.IsEmpty())

【讨论】:

  • +1,我在自己的应用程序中创建了一个扩展方法,因为它更容易阅读“如果为空”然后“如果没有”。
  • +1,查看反射器显示sequence.Any() 是明显的赢家。你有什么理由不想添加这个扩展?..我只是想知道“真的”上的斜体是什么强调的。
  • 一个不错的 IEnumerable IsNullOrEmpty() 扩展方法在这里:haacked.com/archive/2010/06/10/…
  • @Dynami Le Sa​​vard:如果 IEnumerable 的内容尚未计算(例如,您正在使用 Linq),问题是您可能没有意识到您执行了两次:调用 IsEmpty将执行您的 Linq 查询,然后如果它不为空,您可以执行 foreach 并再次重新执行您的查询。
  • @TimLewis 可能是因为它根本不会真正增加任何价值,它只会使 API 更大,因此更难掌握。您会看到 SO-questions 询问 Any 和 IsEmpty 之间的性能差异以及关于哪个更具可读性的讨论等等。如果您个人觉得 Any(或 !Any 字面意思是“不是任何”,对我来说很容易理解)太难以理解,您可以推出自己的包装方法。
【解决方案2】:

您可以使用此实现创建扩展方法。

public static bool IsEmpty<T>(this IEnumerable<T> items) {
        using (var enumerator = items.GetEnumerator())
        {
            return !enumerator.MoveNext();
        }
 }

【讨论】:

  • 嗯,我想这可能是 Any 方法在幕后真正做的事情?
  • 你应该配置枚举器。
  • 仅供未来读者参考:mt_serg 的评论基于此答案的原始版本; Manish 通过更改为 using 解决了这个问题,它会为您处理处置。
【解决方案3】:

您调用的所有这些方法都是 LINQ 扩展方法,因此这取决于 LINQ 提供程序是如何实现的。如果你想知道一个序列是否为空,Count() == 0Any() == false 是合适的。我更喜欢Any()自己。

但是,根据您的 sequence 的实际类型,您可能不需要使用 LINQ 扩展方法。 IE。如果它是一个数组,你可以调用sequence.Length。如果是合集,可以使用sequence.Count

【讨论】:

  • 我不认为推荐Count() == 0Any() == false 是平等的,因为众所周知,对于某些IEnumerables Count 来说要贵得多. Any 肯定是更安全、更优越的选择吗?
  • 我更喜欢Any(),尽管在实践中我很确定某些类型仍然需要在内部进行计数才能返回该结果。此外,Any() 更好地描述了代码的意图,这就是为什么我推荐它而不是 Count()
【解决方案4】:

你说:

if(sequence.Count() == 0) 具有不错的可读性,但性能很差,因为它实际上必须遍历整个序列。

这是真的吗?您正在谈论处理 InterfaceIEnumerable&lt;T&gt;,但您正在对其实现做出假设,这些假设可能正确,也可能不正确。事实上,我多年来编写的许多自定义集合都保留了一个私有变量,用于在内部存储当前计数,这意味着返回 .Count 是一件小事,不需要迭代整个集合。

话虽如此,除非您知道特定实现对.Count 的优化很差,否则我会使用.Count。尽可能避免过早优化,并坚持可读性。

【讨论】:

  • 正如您所说-您正在处理的接口未指定如何计算计数,因此您必须假设它可能是 O(n) 操作。使用Any 而不是Count 是如何过早优化的?使用专门为此目的设计保证 O(1) 时间的方法并不是过早的优化,它根本不是松懈。
  • 嗯,没错。因为我一般不知道它是什么类型的收藏,所以我更愿意安全起见。只要安全方面不是一个极其复杂的方面。在这种情况下,它不是。但是,如果您确实知道它是一个列表或数组,我同意使用CountLength 可能是一个不错的选择。尽管我可能仍会选择坚持使用IsEmpty 扩展方法以保持一致性:)
  • Count 将检查它正在使用的序列是否真的是一个数组,如果是则返回 Length。同样,它将检查 ICollection,并返回 Count。但是序列也可以很容易地成为由迭代器表达式生成的无限序列,在这种情况下,您将等待很长时间才能确定序列是否为空。当您不知道底层序列类型时, Any() 会更加可靠。
  • 如果您使用的是 .NET 2.0?我有点喜欢提醒人们这些来自早期版本的框架 b/c 的“老式”小工件有时人们会忘记并不是每个人都有能力使用最新最好的。
  • 为了以后的读者,我会指出扩展方法 IEnumerable.Count 将检查源是否也是 ICollection 或 ICollection。如果是,则在此接口上调用 Count。否则,扩展方法会枚举整个集合以计数项目。
【解决方案5】:

我使用这个扩展方法来检测序列是否为空或没有任何项目,或者检测序列是否至少有一个项目,就像string.IsNullOrEmpty() 方法一样。

 public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
     if (source == null) {
        return true;
     }

     return !source.Any();
 }

 public static bool IsNotNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
     return !source.IsNullOrEmpty();
 }
 .
 .
 .
 if (!sequence.IsNullOrEmpty()) {
     //Do Something with the sequence...
 }

【讨论】:

  • FWIW,对于第二种方法,我建议使用“HasItems”这个名称 - 比双重否定的“IsNotNullOrEmpty”更短且更具可读性。
  • 糟糕。当我看到您对可能为 null 的值调用方法时,我对此表示反对,但这是我的错误,因为这是一个 extension 方法,因此仍然作为静态方法调用,尽管“。”句法。抱歉,除非编辑答案,否则我删除我的反对票为时已晚。我不明白为什么在这种情况下不允许取消投票。 :(
【解决方案6】:

我有时使用的方法如下:

if(!sequence.Any())

这并不(据我所知)必须经历整个序列, 但可读性有点落后和尴尬。 (读了很多 如果我们检查序列是否为空,则更好)。

  1. 根据微软的说法,Any 确实必须经历整个序列。引用备注部分:

source 的枚举一有结果就停止 确定。

  1. 在测试if-else 语句中是否存在元素时尤其如此。可以说,如果测试if 语句中是否存在元素,以及else 中是否存在元素,则可读性最好,从而避免使用! 运算符:

    if (sequence.Any())
    {
    }
    else
    {
    }
    

    大多数人会认为它比以下更具可读性:

    if (!sequence.Any())
    {
    }
    else
    {
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-04
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多