69

我知道通常空列表比 NULL 更可取。但我要返回 NULL,主要有两个原因

  1. 我必须明确地检查和处理空值,避免错误和攻击。
  2. 之后很容易执行??操作以获得返回值。

对于字符串,我们有 IsNullOrEmpty。C# 本身是否有任何东西对 List 或 IEnumerable 做同样的事情?

4

10 回答 10

77

框架中没有任何内容,但它是一种非常直接的扩展方法。

看这里

/// <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(在可能的情况下)。我不会想到要做的事情。

于 2011-12-20T21:45:04.170 回答
51

后期更新:从 C# 6.0 开始,可以使用空传播运算符来表达简洁,如下所示:

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

或者,作为更清洁和更通用的替代方案IEnumerable<T>

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

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

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

注意2:是必要的,因为以下原因( 此帖子的?? false摘要/引用):

?.null如果子成员是,则运算符将返回null。但是 [...] 如果我们尝试获取一个非Nullable成员,例如 Any()返回bool[...] 的方法,编译器会将返回值“包装”在Nullable<>. 例如,Object?.Any()会给我们bool?(即Nullable<bool>),而不是bool。[...] 因为它不能被隐式转换为bool这个表达式,所以不能在if

注 3:作为奖励,该语句也是“线程安全的”(引自 answer of this question):

在多线程上下文中,如果 [ enumerable ] 可以从另一个线程访问(因为它是一个可访问的字段,或者因为它在暴露给另一个线程的 lambda 中被封闭),那么每次计算时值可能不同 [ ieprior null -检查]

于 2017-01-31T14:05:29.837 回答
25

没有内置任何东西。

这是一个简单的扩展方法:

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

  return !enumerable.Any();
}
于 2011-12-20T21:43:52.333 回答
10
var nullOrEmpty = list == null || !list.Any();
于 2011-12-20T21:46:23.203 回答
3

将前面的答案放在 C# 6.0+ 的简单扩展方法中:

    public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true;
于 2017-03-10T23:37:42.283 回答
1

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

您可以采取不同的方法并将空值变成空值:

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()可以使用等。

于 2011-12-20T23:39:08.430 回答
1

正如其他人所说,框架中没有内置任何内容,但如果您使用的是 Castle,那么 Castle.Core.Internal 就有了。

using Castle.Core.Internal;

namespace PhoneNumbers
{
    public class PhoneNumberService : IPhoneNumberService
    {
        public void ConsolidateNumbers(Account accountRequest)
        {
            if (accountRequest.Addresses.IsNullOrEmpty()) // Addresses is List<T>
            {
                return;
            }
            ...
于 2014-03-19T11:12:52.930 回答
0

我修改了 Matthew Vines 的建议以避免“IEnumerable 的可能多重枚举”问题。(另见 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());
}
于 2016-07-18T10:57:04.640 回答
0
var nullOrEmpty = !( list?.Count > 0 );
于 2016-09-27T11:43:25.617 回答
0

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

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
{
    return !enumerable?.Any() ?? true;
}
于 2019-02-06T08:59:05.510 回答