IEnumerable'ın boş veya boş olup olmadığı nasıl kontrol edilir?


155

string.IsNullOrEmptyMetodu seviyorum . IEnumerable için aynı işlevselliğe izin verecek bir şeye sahip olmak isterim. Böyle var mı? Belki bir koleksiyon yardımcı sınıfı? Sorduğum nedeni, ififadelerde, pıtırtı kodun dağınık görünmesidir (mylist != null && mylist.Any()). Sahip olmak çok daha temiz olurdu Foo.IsAny(myList).

Bu yazı şu cevabı vermiyor: IEnumerable boş mu? .


1
@msarchet: Bu yorum olmasaydı muhtemelen size cevap vereceğim :)
Schultz9999

bana göre bu bir tür XY sorunu gibi görünüyor. "Bu kadar rahatsız edici olmadan null tam olarak her yerde nasıl kontrol edebilirim" sormak yerine "sormalısınız" tasarımımı nasıl geliştirebilirim, böylece her yerde null olup olmadığını kontrol etmek zorunda kalmam? "
sara

@ nawfal, bağlandığınız soru özellikle null çekler içermiyor, bu yüzden yinelenmez
Mygeen

Yanıtlar:


188

Tabii olabilir yazdın:

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

bununla birlikte, tüm dizilerin tekrarlanamayacağına dikkat edin; genellikle , sadece bir kez, her ihtimale karşı yürümeyi tercih ederim.


12
Bu iyi bir model mi? Oraya bırakardım this- nullçirkin tasarımın bir işareti olarak adlandırıldığı varsayılan uzatma yöntemlerini düşünüyorum .
Mormegil

28
@Mormegil Neden? genişletme yöntemleri nihayet C # 'a, diğer dillerin (Ruby gibi) tamamen aldığı null'larla çalışma yeteneği kazandırır.
Matt Greer

5
Bu neden mutlaka kötü? Bu durumda olduğu gibi, bazen çok daha kullanışlıdır, çünkü işleri daha homojen bir şekilde ve daha az özel vaka ile tedavi etmenizi sağlar.
Bay Putty

5
@Mormegil meh - Bu konuda heyecanlanamıyorum. Niyet açık olduğu sürece, vs.
Marc Gravell

6
@Miryafa .Any(), üzerinde çalışan bir uzantı yöntemidir IEnumerable<T>(veya IQueryable<T>farklı bir senaryo olmasına rağmen). Bunu yapmak , diziyi en azından kısmen tüketir (yine de tüketildiği anlamına gelmesine rağmen) - yalnızca bir öğeyi okuması gerekebilir (özellikle yüklem yoksa). Bu nedenle, sekansların ( IEnumerable<T>) tekrarlanabilir olması gerekmediğinden, bu olabilir . Any()yüklem olmadan temelde eşdeğerdir foreach(var x in sequence) { return true; } return false;- GetEnumerator()derleyici sözdizimi yerine etc kullanıyor olsa da
Marc Gravell

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

8
iyi değil, OP IEnumerable istedi, IEnumerable değil <T> ;-)
yoyo

8
Evet, uzantısı IEnumerableyok Any().
Blaise

23

İşte @Matt Greer'in statik bir sarmalayıcı sınıfı içeren kullanışlı cevabının değiştirilmiş bir sürümü, böylece bunu yeni bir kaynak dosyaya kopyalayıp yapıştırabilirsiniz, Linq'e bağlı değildir ve IEnumerable<T>değer türlerinin boksunu önlemek için genel bir aşırı yük ekler bu, genel olmayan sürümde gerçekleşir. [DÜZENLEME: Kullanımının IEnumerable<T>numaralandırıcının boksunu engellemediğini, ördek yazmanın bunu engelleyemeyeceğini, ancak en azından bir değer türündeki koleksiyondaki öğelerin her birinin kutulanmayacağını unutmayın.]

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

Başka bir yol Enumerator almak ve herhangi bir öğe olup olmadığını görmek için MoveNext () yöntemini çağırmak olacaktır:

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

Bu, IEnumerable ve IEnumerable <T> için geçerlidir.


4
Bu numaralandırıcıya imha etme der misiniz? Koleksiyon çok iş parçacığının farkındaysa? Evet. stackoverflow.com/questions/13459447/…
TamusJRoyce

2
@TamusJRoyce IEnumerable<T>Genel olmayanlar IEnumerableuygulamadığı için ifadenizin yalnızca doğru olduğunu unutmayın IDisposable.
Ian Kemp

9

Bazı modern C # özelliklerinden yararlanarak bunu yapıyorum:

Seçenek 1)

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

Seçenek 2)

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

Ve bu arada, asla Count == 0veya Count() == 0sadece bir koleksiyonun boş olup olmadığını kontrol etmek için kullanmayın . Her zaman Linq'leri kullanın.Any()


2
Sayı == 0 gayet iyi .... Belki Any () 'den daha hızlı? Ancak, Count () == 0 hatalı olmak doğru. Merak edenler Count () tüm koleksiyon boyunca yinelenir, bu yüzden çok büyükse bir ton ek yük ekleyebilir!
Anthony Nichols

Count () yalnızca bir ICollection öğesine dönüştürülemediğinde numaralandırmayı yineler. Başka bir deyişle, bu yöntemi çağırdığınızda, nesnede zaten bir Count özelliği varsa, yalnızca bunu döndürür ve performans aynı olmalıdır. Buradaki uygulamaya göz atın: referenceource.microsoft.com/#System.Core/System/Linq/…
Ronald Rey

Bir IEnumerable ile çalışıyorsanız, Linq uygulaması tüm koleksiyon üzerinde yineleneceğinden, Any, yineleyiciyi bir kez hareket ettireceğinden, boşluğu test etmek için Count () kullanmak kesinlikle kötü bir fikirdir. IEnumerable arabiriminin bir parçası olmadığı için Count özelliğini bu durumda kullanamayacağınızı unutmayın. Bu yüzden bence her senaryoda boşlukları test etmek için Any () kullanmak her zaman daha iyi bir fikirdir.
Ronald Rey

!Özellikle ikinci seçenekte okunamayan olumsuzluk operatörünün nasıl olabileceğinin güzel bir örneği ;)
Fabio

6

Bu yardımcı olabilir

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 ile başlayarak null yayılımı kullanabilirsiniz :myList?.Any() == true

Bunu hala çok tıkanık buluyorsanız veya iyi bir genişletme yöntemini tercih ediyorsanız, Matt Greer ve Marc Gravell'in cevaplarını öneririm, ancak tamlık için biraz genişletilmiş işlevsellik ile.

Yanıtları aynı temel işlevselliği sağlar, ancak her biri başka bir bakış açısından. Matt'in cevabı string.IsNullOrEmpty-sellikten yararlanırken, Marc'ın cevabı Linq'in .Any()işi yapmak için yolunu tutuyor .

Ben şahsen .Any()yolu kullanmaya meyilli , ama yöntemin diğer aşırı yük durum kontrolü işlevselliği eklemek istiyorum :

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

Böylece yine de şu gibi şeyler yapabilirsiniz: myList.AnyNotNull(item=>item.AnswerToLife == 42);normalde yapabileceğiniz gibi .Any()ancak eklenen null çek ile

Not C # 6 yolu ile: myList?.Any()bir getiri bool?yerine bir daha boolgerçek etkisidir, çoğaltım boş


1
Koleksiyon? .Any () ile ilgili sorun geçişli değildir. Null olduğunda, toplama? .Any () == true yanlıştır, ancak toplama? .Any () == false da yanlıştır. Ayrıca,! Collection? .Any () == false da yanlıştır ...
Jakub Szuł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

İşte Marc Gravell'in cevabının kodu ve bunu kullanma örneği.

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

Dediği gibi, tüm diziler tekrarlanabilir değildir, böylece kod bazen sorunlara neden olabilir, çünkü IsAny()diziden geçmeye başlar. Robert Harvey'nin cevabının ne anlama geldiğinden şüpheleniyorum , genellikle kontrol etmenize null ve boşaltmanıza gerek yoktur. Genellikle, null olup olmadığını kontrol edip kullanabilirsiniz foreach.

Dizi iki kez başlatmak ve yararlanmak için foreach, sadece böyle bir kod yazdım:

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

Uzatma yöntemi yazarak birkaç satır kaydeder sanırım, ama bu kod benim için daha net görünüyor. Bazı geliştiricilerin bunun IsAny(items)diziye adım atmaya başlayacağını hemen fark etmeyeceğinden şüpheleniyorum . (Elbette çok fazla dizi kullanıyorsanız, hızlı bir şekilde onlardan hangi adımları geçeceğini düşünürsünüz.)


IsAny'yi null olarak çağırırsanız, bir istisna atar
Ace Trajkov

3
Denedin mi, @Ace? Bir istisna atacak gibi görünüyor, ancak boş durumlarda genişletme yöntemleri çağrılabilir .
Don Kirkby

2

Ben kullanıyorum Bool IsCollectionNullOrEmpty = !(Collection?.Any()??false);. Bu yardımcı olur umarım.

Yıkmak:

Collection?.Any()Koleksiyon boşsa nullve falseKoleksiyon boşsa geri döner .

Collection?.Any()??falsefalseKoleksiyon boşsa ve falseKoleksiyon boşsa bize verir null.

Bunun tamamlayıcısı bize verecek IsEmptyOrNull.


2

Jon Skeet'in kullanıcısı ( https://stackoverflow.com/a/28904021/8207463 ) NULL ve EMPTY için Extension Method - Any () kullanarak iyi bir yaklaşıma sahiptir. AMA NULL DEĞİL durumunda soru sahibini doğrular. Jon´'un yaklaşımını AS NULL olarak doğrulamak için dikkatlice değiştirin:

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

KULLANMAYIN (NULL OLARAK doğrulanmaz):

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

Doğrulamanın AS NOT NULL (örnek olarak test EDİLMİYOR, ancak derleyici hatası olmadan) durumunda yüklemeyi kullanmak gibi bir şey yapabilirsiniz:

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

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

Hangi .NET sürümü için kullanabileceğinizi kontrol edin:

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


1

Aynı sorunu yaşadım ve şu şekilde çözdüm:

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

"c => c! = null" tüm boş varlıkları yok sayar.


1

Bunu @Matt Greer tarafından cevaplandırıldım

OP'nin sorusuna mükemmel cevap verdi.

Herhangi biri orijinal yeteneklerini korurken de null kontrol ederken böyle bir şey istedim. Başka birinin benzer bir şeye ihtiyacı olması durumunda bunu gönderiyorum.

Özellikle bir yüklemden geçmek istiyordum.

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

Genişletme yönteminin adlandırılması muhtemelen daha iyi olabilir.


0

Aşağıdaki gibi en iyi çözüm boş kontrol etmek ya da değil?

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

1
Eğer listEnumerablebu soru null olursa işe yaramaz
Timotei

0

Bunu kullanıyorum:

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

ejem:

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

0

Bir okumadan sonra bazı kaynaklar tükendiğinden, geleneksel ayrı kontrol yerine kontrolleri ve okumaları neden birleştirmeyip, sonra okuduğumu düşündüm.

Öncelikle, daha basit null denetimi için satır içi uzantı için bir tane var:

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

Sonra null ve boş satır içi uzantısı için biraz daha ilgili (en azından yazdığım şekilde) var:

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

Elbette, çağrı zincirine devam etmeden her ikisini de arayabilirsiniz. Ayrıca, paramName ekledim, böylece arayan "kaynak" kontrol edilmiyorsa, örneğin "nameof (hedef)" hatası için alternatif bir ad içerebilir.


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

kontrol etmek için kendi uzantısı yöntemi null değil ve herhangi


0

Özel yardımcılar olmadan ya nispeten özlü ya ?.Any() ?? falseda ?.Any() == truediziyi yalnızca bir kez belirtmeniz gerekenleri öneririm .


Eksik bir koleksiyonu boş bir koleksiyon gibi ele almak istediğimde, aşağıdaki uzantı yöntemini kullanıyorum:

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

Bu işlev tüm LINQ yöntemleriyle birleştirilebilir ve foreachsadece .Any()bu değil , bu yüzden insanların burada önerdiği daha uzmanlaşmış yardımcı işlevlere tercih ediyorum.


0

kullanırım

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

Eşleşme yoksa sonuç null olur, aksi takdirde nesnelerden birini döndürür

Listeyi isterseniz, First () 'den ayrılmak veya ToList ()' i çağırmak listeyi veya null değerini sağlayacağına inanıyorum.


0

Şu açık kaynak kütüphanesine bir göz atın: Nzr.ToolBox

public static bool IsEmpty(this System.Collections.IEnumerable enumerable)

-1

eklemek using System.Linqve mevcut yöntemlere erişmeye çalıştığınızda gerçekleşen büyüyü görmek IEnumerable. Bunu eklemek, bu Count()kadar basit adlı bir yönteme erişmenizi sağlar . Sadece null valuearamadan önce kontrol etmeyi unutmayın count():)


-1

Kontrol etmek için basit kullandım

çözümümü kontrol et

foreach (Pet pet in v.Pets)
{
    if (pet == null)
    {
        Console.WriteLine(" No pet");// enumerator is empty
        break;
    }
    Console.WriteLine("  {0}", pet.Name);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.