ChatGPT解决这个技术问题 Extra ChatGPT

如何检查 IEnumerable 是 null 还是空?

我喜欢 string.IsNullOrEmpty 方法。我很想拥有一些允许 IEnumerable 具有相同功能的东西。有这样的吗?也许一些收集助手类?我问的原因是在 if 语句中,如果模式是 (mylist != null && mylist.Any()),代码看起来很混乱。有 Foo.IsAny(myList) 会干净得多。

这篇文章没有给出这个答案:IEnumerable is empty?

@msarchet:如果这不是评论,我可能会给你答案:)
对我来说,这似乎是一个 XY 问题。而不是问“我怎样才能在不那么麻烦的情况下准确地检查null”,而应该问“我怎样才能改进我的设计,这样我就不必到处检查null了?”
您可以改用以下行:myCollection?.FirstOrDefault() == null

M
Marc Gravell

当然你可以这样写:

public static class Utils {
    public static bool IsAny<T>(this IEnumerable<T> data) {
        return data != null && data.Any();
    }
}

但是,请注意并非所有序列都是可重复的;一般来说,我宁愿只走一次,以防万一。


这是一个好的模式吗?我会把 this 放在那里——我认为假定在 null 上调用的扩展方法是丑陋设计的标志。
@Mormegil 为什么?扩展方法最终赋予 C# 一些处理空值的能力,而其他语言(如 Ruby)完全认为这是理所当然的。
为什么这必然是坏事?在这种情况下,它有时非常方便,因为它可以让您更均匀地处理事物并减少特殊情况。
@Mormegil meh - 我对此兴奋不已。只要意图明确,等等。
@Miryafa .Any() 是在 IEnumerable<T>(或 IQueryable<T> 上运行的扩展方法,尽管这是不同的场景)。这样做消耗序列,至少部分(尽管这仍然意味着它被消耗) - 它可能只需要读取一个元素(尤其是在没有谓词的情况下)。因此,由于序列 (IEnumerable<T>) 不需要是可重复的,可能就是这样。没有谓词的 Any() 基本上 等同于 foreach(var x in sequence) { return true; } return false; - 尽管它使用 GetEnumerator() 等而不是编译器语法
M
Matt Greer
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable) {
    return enumerable == null || !enumerable.Any();
}

好吧,不完全是,OP 要求 IEnumerable,而不是 IEnumerable ;-)
是的,IEnumerable 没有 Any() 扩展名。
添加 System.Linq 以启用 Any() 扩展
y
yoyo

这是@Matt Greer 的有用答案的修改版本,其中包括一个静态包装类,因此您可以将其复制粘贴到一个新的源文件中,不依赖于 Linq,并添加了一个通用的 IEnumerable<T> 重载,以避免装箱非泛型版本会出现的值类型。 [编辑:请注意,使用 IEnumerable<T> 不会阻止枚举数的装箱,duck-typing 不能阻止,但至少值类型集合中的元素不会被装箱。]

using System.Collections;
using System.Collections.Generic;

public static class IsNullOrEmptyExtension
{
    public static bool IsNullOrEmpty(this IEnumerable source)
    {
        if (source != null)
        {
            foreach (object obj in source)
            {
                return false;
            }
        }
        return true;
    }

    public static bool IsNullOrEmpty<T>(this IEnumerable<T> source)
    {
        if (source != null)
        {
            foreach (T obj in source)
            {
                return false;
            }
        }
        return true;
    }
}

D
Darren

另一种方法是获取 Enumerator 并调用 MoveNext() 方法以查看是否有任何项目:

if (mylist != null && mylist.GetEnumerator().MoveNext())
{
    // The list is not null or empty
}

这适用于 IEnumerable 和 IEnumerable


你应该在这个枚举器上调用 dispose 吗?如果集合是多线程感知的?是的。 stackoverflow.com/questions/13459447/…
@TamusJRoyce 请注意,您的陈述仅适用于 IEnumerable<T>,因为非泛型 IEnumerable 不实现 IDisposable
R
Ronald Rey

我这样做的方式是利用一些现代 C# 功能:

选项1)

public static class Utils {
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
        return !(list?.Any() ?? false);
    }
}

选项 2)

public static class Utils {
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> list) {
        return !(list?.Any()).GetValueOrDefault();
    }
}

顺便说一句,切勿使用 Count == 0Count() == 0 来检查集合是否为空。始终使用 Linq 的 .Any()


Count == 0 就好了....可能比 Any() 更快?但是,您对 Count() == 0 不好是正确的。对于那些想知道 Count() 遍历整个集合的人,所以如果它很大可能会增加大量开销!
Count() 仅在无法强制转换为 ICollection 时迭代枚举。换句话说,当你调用这个方法时,如果对象上已经有一个 Count 属性,它只会返回它,并且性能应该是相同的。在此处查看实施:referencesource.microsoft.com/#System.Core/System/Linq/…
如果您正在使用 IEnumerable,则使用 Count() 来测试是否为空绝对是一个坏主意,因为 Linq 实现将遍历整个集合,而 Any 只会移动迭代器一次。请记住,在这种情况下您不能使用 Count 属性,因为它不是 IEnumerable 接口的一部分。这就是为什么在我看来,在所有场景中使用 Any() 来测试是否为空总是一个更好的主意。
不可读的否定运算符 ! 的好例子,特别是在第二个选项中;)
S
Scholtz
if (collection?.Any() == true){
    // if collection contains more than one item
}
if (collection?.Any() != true){
    // if collection is null
    // if collection does not contain any item
}

T
Thomas Mulder

从 C#6 开始,您可以使用 null propagationmyList?.Any() == true

如果您仍然觉得这太麻烦或者更喜欢一个好的 ol' 扩展方法,我会推荐 Matt Greer 和 Marc Gravell 的答案,但为了完整性,需要一些扩展功能。

他们的答案提供了相同的基本功能,但每个都从另一个角度。 Matt 的答案使用了 string.IsNullOrEmpty 心态,而 Marc 的答案则采用了 Linq 的 .Any() 方法来完成工作。

我个人倾向于使用 .Any() 路,但想从方法的 other overload 添加条件检查功能:

    public static bool AnyNotNull<T>(this IEnumerable<T> source, Func<T, bool> predicate = null)
    {
        if (source == null) return false;
        return predicate == null
            ? source.Any()
            : source.Any(predicate);
    }

因此,您仍然可以像使用常规 .Any() 一样执行以下操作:myList.AnyNotNull(item=>item.AnswerToLife == 42);,但添加了 null 检查

请注意,使用 C#6 方式:myList?.Any() 返回一个 bool? 而不是 bool,这是 propagating null 的实际效果


collection?.Any() 的问题在于它不具有传递性。当为空时,collection?.Any() == true 为 false,但 collection?.Any() == false 也为 false。此外, !collection?.Any() == false 也是假的......
H
Hossein Narimani Rad

这可能会有所帮助

public static bool IsAny<T>(this IEnumerable<T> enumerable)
{
    return enumerable?.Any() == true;
}

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
    return enumerable?.Any() != true;
}

J
Just Fair

Jon Skeet 的 anwser (https://stackoverflow.com/a/28904021/8207463) 有一个使用扩展方法的好方法 - Any() 用于 NULL 和 EMPTY。但他正在验证问题的所有者,以防不为空。因此,请小心地将 Jon 验证 AS NULL 的方法更改为:

If (yourList?.Any() != true) 
{
     ..your code...
}

不要使用(不会验证为 NULL):

If (yourList?.Any() == false) 
{
     ..your code...
}

您还可以在验证 AS NOT NULL 的情况下(未测试仅作为示例但没有编译器错误)执行类似使用谓词的操作:

If (yourList?.Any(p => p.anyItem == null) == true) 
{
     ..your code...
}

https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,8788153112b7ffd0

您可以使用哪个 .NET 版本,请检查:

https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any?view=netframework-4.8#moniker-applies-to


C
Community

这是来自 Marc Gravell's answer 的代码,以及使用它的示例。

using System;
using System.Collections.Generic;
using System.Linq;

public static class Utils
{
    public static bool IsAny<T>(this IEnumerable<T> data)
    {
        return data != null && data.Any();
    }
}

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<string> items;
        //items = null;
        //items = new String[0];
        items = new String[] { "foo", "bar", "baz" };

        /*** Example Starts Here ***/
        if (items.IsAny())
        {
            foreach (var item in items)
            {
                Console.WriteLine(item);
            }
        }
        else
        {
            Console.WriteLine("No items.");
        }
    }
}

正如他所说,并非所有序列都是可重复的,因此代码有时可能会导致问题,因为 IsAny() 开始逐步遍历序列。我怀疑 Robert Harvey's answer 的意思是您通常不需要检查 null 是否为空。通常,您可以只检查 null,然后使用 foreach

为避免启动序列两次并利用 foreach,我只编写了如下代码:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<string> items;
        //items = null;
        //items = new String[0];
        items = new String[] { "foo", "bar", "baz" };

        /*** Example Starts Here ***/
        bool isEmpty = true;
        if (items != null)
        {
            foreach (var item in items)
            {
                isEmpty = false;
                Console.WriteLine(item);
            }
        }
        if (isEmpty)
        {
            Console.WriteLine("No items.");
        }
    }
}

我想扩展方法可以为您节省几行打字,但这段代码对我来说似乎更清晰。我怀疑一些开发人员不会立即意识到 IsAny(items) 实际上会开始逐步执行该序列。 (当然,如果你使用了很多序列,你很快就会学会思考它们的步骤。)


如果您在 null 上调用 IsAny,它将引发异常
你试过了吗,@Ace?看起来它会引发异常,但是 extension methods can be called on null instances
S
Sabyasachi Mukherjee

我使用 Bool IsCollectionNullOrEmpty = !(Collection?.Any()??false);。希望这可以帮助。

分解:

如果 Collection 为空,Collection?.Any() 将返回 null,如果 Collection 为空,则返回 false

如果 Collection 为空,Collection?.Any()??false 将为我们提供 false,如果 Collection 为 null,则为 false

对此的补充将给我们IsEmptyOrNull


A
Adel Tabareh

当它是关于引用(可为空)类型以及项目中预期没有空项目时,可以使用这一行进行验证

myCollection?.FirstOrDefault() == null

H
Hosein Djadidi

我有同样的问题,我像这样解决它:

    public bool HasMember(IEnumerable<TEntity> Dataset)
    {
        return Dataset != null && Dataset.Any(c=>c!=null);
    }

"c=>c!=null" 将忽略所有空实体。


K
Keith Banner

我在 answer by @Matt Greer 的基础上构建了这个

他完美地回答了OP的问题。

我想要这样的东西,同时保持 Any 的原始功能,同时还检查 null。我发布这个以防其他人需要类似的东西。

具体来说,我希望仍然能够传递谓词。

public static class Utilities
{
    /// <summary>
    /// Determines whether a sequence has a value and contains any elements.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">The <see cref="System.Collections.Generic.IEnumerable"/> to check for emptiness.</param>
    /// <returns>true if the source sequence is not null and contains any elements; otherwise, false.</returns>
    public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source)
    {
        return source?.Any() == true;
    }

    /// <summary>
    /// Determines whether a sequence has a value and any element of a sequence satisfies a condition.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="System.Collections.Generic.IEnumerable"/> whose elements to apply the predicate to.</param>
    /// <param name="predicate">A function to test each element for a condition.</param>
    /// <returns>true if the source sequence is not null and any elements in the source sequence pass the test in the specified predicate; otherwise, false.</returns>
    public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
        return source?.Any(predicate) == true;
    }
}

扩展方法的命名可能会更好。


B
Basheer AL-MOMANI

我用简单的 if 来检查它

查看我的解决方案

foreach (Pet pet in v.Pets)
{
    if (pet == null)
    {
        Console.WriteLine(" No pet");// enumerator is empty
        break;
    }
    Console.WriteLine("  {0}", pet.Name);
}

S
Shakeer Hussain

下面的另一个最佳解决方案是检查是否为空?

for(var item in listEnumerable)
{
 var count=item.Length;
  if(count>0)
  {
         // not empty or null
   }
  else
  {
       // empty
  }
}

如果 listEnumerable 为空,这将不起作用,这是手头的问题
J
Jhollman

我用这个:

    public static bool IsNotEmpty(this ICollection elements)
    {
        return elements != null && elements.Count > 0;
    }

埃杰姆:

List<string> Things = null;
if (Things.IsNotEmpty())
{
    //replaces ->  if (Things != null && Things.Count > 0) 
}

R
Rob

由于一些资源在一次读取后耗尽,我想为什么不将检查和读取结合起来,而不是传统的单独检查,然后读取。

首先,我们有一个更简单的 check-for-null 内联扩展:

public static System.Collections.Generic.IEnumerable<T> ThrowOnNull<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null) => source ?? throw new System.ArgumentNullException(paramName ?? nameof(source));

var first = source.ThrowOnNull().First();

然后我们有更多的参与(嗯,至少我写它的方式)check-for-null-and-empty inline extension:

public static System.Collections.Generic.IEnumerable<T> ThrowOnNullOrEmpty<T>(this System.Collections.Generic.IEnumerable<T> source, string paramName = null)
{
  using (var e = source.ThrowOnNull(paramName).GetEnumerator())
  {
    if (!e.MoveNext())
    {
      throw new System.ArgumentException(@"The sequence is empty.", paramName ?? nameof(source));
    }

    do
    {
      yield return e.Current;
    }
    while (e.MoveNext());
  }
}

var first = source.ThrowOnNullOrEmpty().First();

当然,您仍然可以在不继续调用链的情况下同时调用两者。此外,我还包含了 paramName,以便调用者可以包含错误的备用名称,如果它不是被检查的“源”,例如“nameof(target)”。


A
Ahmed Salem
 public static bool AnyNotNull<TSource>(this IEnumerable<TSource> source)
    {
        return source != null && source.Any();
    }

我自己的扩展方法来检查 Not null 和 Any


C
CodesInChaos

如果没有自定义助手,我推荐使用 ?.Any() ?? false?.Any() == true,它们相对简洁,只需要指定一次序列。

当我想将丢失的集合视为空集合时,我使用以下扩展方法:

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

此函数可以与所有 LINQ 方法和 foreach 组合,而不仅仅是 .Any(),这就是为什么我更喜欢它而不是人们在这里提出的更专业的帮助函数。


R
Ron Chibnik

我用

    list.Where (r=>r.value == value).DefaultIfEmpty().First()

如果不匹配,结果将为 null,否则返回其中一个对象

如果您想要列表,我相信离开 First() 或调用 ToList() 将提供列表或 null。


T
Truong Mai Van

它 null 将返回 true

enter    public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
    {

        try
        {
            return enumerable?.Any() != true;
        }
        catch (Exception)
        {

            return true;
        }
   
    }

代码在这里


c
caldera.sac

只需添加 using System.Linq 并在您尝试访问 IEnumerable 中的可用方法时看到神奇的发生。添加它将使您能够像这样简单地访问名为 Count() 的方法。请记住在调用 count() 之前检查 null value :)