对于 List/IEnumable,C # 有 IsNullOrEmpty 吗?

我知道一般来说空 List 比 NULL 更好。但是我将返回 NULL,主要有两个原因

  1. 我必须显式地检查和处理 null 值,以避免 bug 和攻击。
  2. 之后很容易执行 ??操作来获得返回值。

对于字符串,我们有 IsNullOrEmpty。有没有什么 从 C # 本身对 List 或 IEnumable 做同样的事情?

91867 次浏览

没有什么是内置的。

不过,这是一种简单的扩展方法:

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
if(enumerable == null)
return true;


return !enumerable.Any();
}

框架中没有内置任何东西,但它是一个非常直接的扩展方法。

看这里

/// <summary>
/// Determines whether the collection is null or contains no elements.
/// </summary>
/// <typeparam name="T">The IEnumerable type.</typeparam>
/// <param name="enumerable">The enumerable, which may be null or empty.</param>
/// <returns>
///     <c>true</c> if the IEnumerable is null or empty; otherwise, <c>false</c>.
/// </returns>
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
return true;
}
/* If this is a list, use the Count property for efficiency.
* The Count property is O(1) while IEnumerable.Count() is O(N). */
var collection = enumerable as ICollection<T>;
if (collection != null)
{
return collection.Count < 1;
}
return !enumerable.Any();
}

出于性能方面的考虑,Daniel Vaughan 采取了向 ICollection (如果可能的话)进行强制转换的额外步骤。我从没想过要这么做。

var nullOrEmpty = list == null || !list.Any();

如果您需要能够在元素不为空的情况下检索所有元素,那么这里的一些答案将不起作用,因为对不可重复枚举的 Any()的调用将“忘记”一个元素。

您可以采用一种不同的方法,将 null 转换为空值:

bool didSomething = false;
foreach(var element in someEnumeration ?? Enumerable.Empty<MyType>())
{
//some sensible thing to do on element...
didSomething = true;
}
if(!didSomething)
{
//handle the fact that it was null or empty (without caring which).
}

同样,(someEnumeration ?? Enumerable.Empty<MyType>()).ToList()等也可以使用。

正如其他人所说,框架中没有内置任何东西,但是如果您使用 Castle,那么使用 Castle。核心。内务部有。

using Castle.Core.Internal;


namespace PhoneNumbers
{
public class PhoneNumberService : IPhoneNumberService
{
public void ConsolidateNumbers(Account accountRequest)
{
if (accountRequest.Addresses.IsNullOrEmpty()) // Addresses is List<T>
{
return;
}
...

我修改了 Matthew Vines 的建议,以避免“ IEnumable 的可能多枚举”问题。 (参见 Jon Hanna 的评论)

public static bool IsNullOrEmpty(this IEnumerable items)
=> items == null
|| (items as ICollection)?.Count == 0
|| !items.GetEnumerator().MoveNext();

还有单元测试:

[Test]
public void TestEnumerableEx()
{
List<int> list = null;
Assert.IsTrue(list.IsNullOrEmpty());


list = new List<int>();
Assert.IsTrue(list.IsNullOrEmpty());


list.AddRange(new []{1, 2, 3});
Assert.IsFalse(list.IsNullOrEmpty());


var enumerator = list.GetEnumerator();
for(var i = 1; i <= list.Count; i++)
{
Assert.IsFalse(list.IsNullOrEmpty());
Assert.IsTrue(enumerator.MoveNext());
Assert.AreEqual(i, enumerator.Current);
}


Assert.IsFalse(list.IsNullOrEmpty());
Assert.IsFalse(enumerator.MoveNext());
}
var nullOrEmpty = !( list?.Count > 0 );

后期更新 : 自 C # 6.0以来,空传播算子可以用来表达这样的简洁:

if (  list?.Count  > 0 ) // For List<T>
if ( array?.Length > 0 ) // For Array<T>

或者,作为 IEnumerable<T>更清洁、更通用的替代品:

if ( enumerable?.Any() ?? false )

注1: 与 OP 问题(引用)相比,所有上部变体实际上都反映了 IsNotNullOrEmpty:

由于操作符优先级,IsNullOrEmpty等价物看起来不那么吸引人:
if (!(list?.Count > 0))

注2: 由于以下原因(摘要/引自 这篇文章) ,必须使用 ?? false:

如果子成员是 null,则 ?.操作符将返回 null。 但是[ ... ]如果我们试图得到一个非 Nullable成员,像 方法,该方法返回编译器将返回的 bool[ ... ] 在 Nullable<>中“包装”一个返回值。例如,Object?.Any()将 给我们 bool?(即 Nullable<bool>) ,而不是 bool。 [ ... ]因为它不能隐式转换为 bool,所以这个表达式不能在 if中使用

注3: 作为奖励,该语句也是“线程安全的”(引自 这个问题的答案) :

在多线程上下文中,如果[ 数不胜数]可以从另一个 线程(或者因为它是可访问的字段,或者因为它是 关闭在一个 lambda 中,该 lambda 暴露于另一个线程) ,然后 值在每次计算时可能不同[ 也就是之前的无效检查]

将前面的答案组合成一个简单的 C # 6.0 + 扩展方法:

    public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true;

对我来说最好的是 isNullOrEmpty 方法看起来是这样的

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

using var enumerator = enumerable.GetEnumerator();
 

var isEmpty = !enumerator.MoveNext();
 

return isEmpty;
}
}

带有可空支持的一行代码:

public static bool IsNullOrEmpty<T>(this IEnumerable<T>? enumerable) =>
enumerable == null || !enumerable.Any();