IEnumerableがnullまたは空かどうかを確認する方法


154

私はstring.IsNullOrEmpty方法が大好きです。IEnumerableに同じ機能を許可するものが欲しいです。そのようなものはありますか?たぶんコレクションヘルパークラス?私が尋ねる理由は、ifステートメントでは、パターンがそうだとコードが乱雑に見えるからです(mylist != null && mylist.Any())。持つ方がはるかにクリーンになりますFoo.IsAny(myList)

この投稿はその答えを与えません:IEnumerableは空ですか?


1
@msarchet:これがコメントでない場合は、おそらく答えを出します:)
Schultz9999

私には、これは一種のXY問題のように思えます。「煩わしいことなく、どこでもヌルを正確にチェックするにはどうすればよいですか」と尋ねる代わりに、「どこでもヌルをチェックする必要がないように、デザインを改善するにはどうすればよいですか?」
サラ

@nawfal、あなたがリンクした質問には特にnullチェックが含まれていないため、重複とは見なしません
Mygeen

回答:


188

確かにあなたはそれを書くことができます:

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

ただし、すべてのシーケンスが反復可能であるとは限らないことに注意してください。一般的に、念のために一度だけ歩くことを好みます。


12
これは良いパターンですか?私はthisそこを落とします-私nullは醜いデザインのしるしとして呼ばれると想定される拡張メソッドを考えます。
Mormegil

28
@Mormegilなんで?拡張メソッドは、他の言語(Rubyなど)が完全に当然のことと考えているnullを処理する機能をC#に最終的に提供します。
マットグリア

5
なぜこれは必ずしも悪いのですか?この場合のように、物事をより均一に扱うことができ、特殊なケースが少ないため、非常に便利な場合があります。
パティ氏、2011

5
@Mormegil meh-私はそれについて興奮することはできません。意図が明確である
かぎり

6
@Miryafa .Any()は、動作する拡張メソッドですIEnumerable<T>(またはIQueryable<T>、これは別のシナリオですが)。そうすることで、少なくとも部分的にシーケンスを消費します(ただし、それでも消費されることを意味します)。1つの要素を読み取るだけで十分な場合があります(特に述語がない場合)。そのため、シーケンス(IEnumerable<T>)は反復可能である必要はないので、それだけかもしれませんAny()述語なしの場合は、コンパイラ構文の代わりにetcを使用しますが、基本的に同等ですforeach(var x in sequence) { return true; } return false;GetEnumerator()
Marc Gravell

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

8
そうですね、まあ、OPはIEnumerable <T>ではなくIEnumerableを要求しました;-)
yoyo

8
はい、拡張子IEnumerableはありませんAny()
ブレーズ

23

これは、静的ラッパークラスを含む、@ Matt Greerの便利な回答の変更バージョンです。これにより、これを新しいソースファイルにコピーアンドペーストでき、Linqに依存せず、一般的なIEnumerable<T>オーバーロードを追加して、値型のボックス化を回避できます。これは、非ジェネリックバージョンで発生します。[編集:の使用はIEnumerable<T>列挙子のボックス化を妨げないことに注意してください。ダックタイピングはそれを防ぐことはできませんが、少なくとも値型コレクションの要素はそれぞれボックス化されません。]

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;
    }
}

15

もう1つの方法は、Enumeratorを取得してMoveNext()メソッドを呼び出し、アイテムがあるかどうかを確認することです。

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

これは、IEnumerableおよびIEnumerable <T>で機能します。


4
この列挙子でdisposeを呼び出す必要がありますか?コレクションがマルチスレッド対応である場合はどうなりますか?はい。stackoverflow.com/questions/13459447/...
TamusJRoyce

2
@TamusJRoyce IEnumerable<T>非ジェネリックIEnumerableは実装していないため、ステートメントはに対してのみ真であることに注意してくださいIDisposable
Ian Kemp

9

私のやり方は、いくつかの最新の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 == 0たり、使用したりしCount() == 0ないでください。常にLinqを使用する.Any()


2
Count == 0で十分です。Any()より高速かもしれません。しかし、あなたはCount()== 0が悪いことで正しいです。Count()が不思議に思っている場合は、コレクション全体を反復処理するので、それが非常に大きい場合、大量のオーバーヘッドが追加される可能性があります。
Anthony Nichols

Count()は、ICollectionにキャストできない場合にのみ列挙を反復します。つまり、このメソッドを呼び出すときに、オブジェクトに既にCountプロパティがある場合、それはそれを返すだけで、パフォーマンスは同じになります。ここでの実装をチェックアウト:referencesource.microsoft.com/#System.Core/System/Linq/...
ロナルド・レイ

IEnumerableで作業している場合、Count()を使用して空かどうかをテストすることは間違いなく悪い考えです。Linq実装はコレクション全体を反復しますが、Anyは反復子を1回だけ移動します。この場合、CountプロパティはIEnumerableインターフェイスの一部ではないため、使用できないことに注意してください。私の意見では、すべてのシナリオで空かどうかをテストするためにAny()を使用するほうが常に良い考えです。
ロナルドレイ

!特に2番目のオプションで、読み取り不能な否定演算子がどのように使用できるかを示す良い例;)
Fabio

6

これは役立つかもしれません

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;
}

5

C#6以降では、null伝播を使用できますmyList?.Any() == true

それでもこれがわかりづらい、または古き良き拡張方法を好む場合は、マットグリアとマークグラベルの回答をお勧めします。

彼らの答えは同じ基本機能を提供しますが、それぞれ別の観点からです。マットの答えはstring.IsNullOrEmpty-mentalityを使用していますが、マルクの答えはLinqの答えを取ります.Any()が仕事を道をます。

私は個人的に.Any()道路を使用する傾向がありますが、メソッドの他のオーバーロードから条件チェック機能を追加したいと思います:

    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);
    }

だから、あなたはまだのようなmyList.AnyNotNull(item=>item.AnswerToLife == 42);ことをすることができます:通常と同じように .Any()、追加されたnullチェックで

なお、C#6の方法と:myList?.Any()戻るbool?のではなくbool、実際の効果であり、伝搬ヌル


1
collection?.Any()の問題は、推移的でないことです。nullの場合、collection?.Any()== trueはfalseですが、collection?.Any()== falseもfalseです。さらに、!collection?.Any()== falseもfalseです...
JakubSzułakiewicz

4
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
}

2

以下は、Marc Gravellの回答のコードと、その使用例です。

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の答えが何を意味していたかは、多くの場合、チェックしnull 空にする必要がないことだと思います。多くの場合、nullを確認してから使用できますforeach

シーケンスの2回の開始を回避してを利用するために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 Trajkov 2013

3
やってみましたか、@エース?例外をスローするように見えますが、拡張メソッドはnullインスタンスで呼び出すことができます
Don Kirkby 2013

2

使用しますBool IsCollectionNullOrEmpty = !(Collection?.Any()??false);。お役に立てれば。

壊す:

Collection?.Any()nullコレクションがnullのfalse場合、およびコレクションが空の場合に返されます。

Collection?.Any()??false私たちを与えるfalseコレクションが空の場合、およびfalseコレクションがある場合null

それを補完してくれIsEmptyOrNullます。


2

Jon Skeetのanwser(https://stackoverflow.com/a/28904021/8207463)は、拡張メソッド-Any ()をNULLとEMPTYに使用する優れたアプローチを持っています。しかし、彼はNOT NULLの場合に備えて質問の所有者を検証しています。したがって、JonのアプローチをAS NULLを検証するように慎重に変更します。

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

使用しないでください(AS 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


1

私は同じ問題を抱えており、私はそれを次のように解決します:

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

「c => c!= null」はすべてのnullエンティティを無視します。


1

私は@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;
    }
}

拡張メソッドの命名はおそらくもっと良いでしょう。


0

空かどうかをチェックする以下のような他の最良の解決策はありますか?

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

1
それがlistEnumerable手元の問題であるnullである場合、それは機能しません
Timotei '25 / 07/25

0

私はこれを使います:

    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) 
}

0

1回の読み取りでいくつかのリソースが使い果たされるので、従来の個別のチェックではなく、チェックと読み取りを組み合わせてから、読み取りを実行してみませんか。

最初に、より単純なnullのチェックのインライン拡張用の1つがあります。

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();

次に、もう少し複雑になります(少なくとも、私が書いた方法で)、null-and-emptyのインライン拡張をチェックします。

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)」などの「ソース」がチェックされていない場合に、呼び出し元がエラーの代替名を含めることができます。


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

Not nullおよびAnyをチェックするための独自の拡張メソッド


0

カスタムヘルパーがない?.Any() ?? false場合?.Any() == trueは、どちらか、または比較的簡潔で、シーケンスを1回指定するだけで済むことをお勧めします。


不足しているコレクションを空のコレクションのように扱いたい場合は、次の拡張メソッドを使用します。

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

この関数はforeach、だけでなく、すべてのLINQメソッドと組み合わせることができます.Any()。そのため、ここで人々が提案しているより専門的なヘルパー関数よりもこの関数を好みます。


0

私が使う

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

一致しない場合、結果はnullになります。それ以外の場合は、オブジェクトの1つを返します

リストが必要な場合は、First()を終了するか、ToList()を呼び出すと、リストまたはnullが提供されると思います。



-1

追加using System.Linqして、で使用可能なメソッドにアクセスしようとしたときに発生する魔法を確認してくださいIEnumerable。これを追加するとCount()、そのように単純な名前のメソッドにアクセスできるようになります。null value呼び出す前に確認してくださいcount():)


-1

それをチェックする場合、私は単純に使用しました

私の解決策をチェックしてください

foreach (Pet pet in v.Pets)
{
    if (pet == null)
    {
        Console.WriteLine(" No pet");// enumerator is empty
        break;
    }
    Console.WriteLine("  {0}", pet.Name);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.