Bagaimana memeriksa apakah IEnumerable adalah nol atau kosong?

155

Saya suka string.IsNullOrEmptymetode. Saya ingin memiliki sesuatu yang memungkinkan fungsi yang sama untuk IEnumerable. Apakah ada? Mungkin beberapa kelas penolong koleksi? Alasan saya bertanya adalah bahwa dalam ifpernyataan kode terlihat berantakan jika derai itu (mylist != null && mylist.Any()). Akan jauh lebih bersih untuk dimiliki Foo.IsAny(myList).

Posting ini tidak memberikan jawaban itu: IEnumerable kosong? .

Schultz9999
sumber
1
@msarchet: Saya mungkin akan memberi Anda jawaban jika ini bukan komentar :)
Schultz9999
bagi saya ini sepertinya semacam masalah XY. alih-alih bertanya "bagaimana saya bisa mengecek nol di mana-mana tanpa menyusahkan" Anda harus bertanya "bagaimana saya bisa memperbaiki desain saya sehingga saya tidak HARUS memeriksa nol di mana-mana?"
sara
@nawfal, pertanyaan yang Anda tautkan tidak menyertakan cek khusus, jadi saya tidak akan menganggapnya sebagai duplikat
Mygeen

Jawaban:

188

Tentu Anda bisa menulis itu:

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

Namun, berhati-hatilah agar tidak semua urutan dapat diulang; umumnya saya lebih suka hanya berjalan sekali, untuk berjaga-jaga.

Marc Gravell
sumber
12
Apakah ini pola yang baik? Saya akan menjatuhkan di thissana - saya mempertimbangkan metode ekstensi yang dianggap dipanggil nullsebagai tanda desain yang jelek.
Mormegil
28
@ Magormil Mengapa? metode ekstensi akhirnya memberi C # beberapa kemampuan untuk bekerja dengan nol, yang bahasa lain (seperti Ruby) sepenuhnya menerima begitu saja.
Matt Greer
5
Mengapa ini selalu buruk? Seperti dalam kasus ini, kadang-kadang sangat berguna karena memungkinkan Anda memperlakukan sesuatu dengan lebih homogen dan dengan lebih sedikit kasus khusus.
Tn. Putty
5
@ Mormegil meh - Saya tidak bisa bersemangat tentang itu. Sepanjang tujuannya jelas, dll.
Marc Gravell
6
@Miryafa .Any()adalah metode ekstensi yang beroperasi padaIEnumerable<T> (atau IQueryable<T>, meskipun itu skenario yang berbeda). Melakukan hal itu menghabiskan urutan , setidaknya sebagian (meskipun itu masih berarti dikonsumsi) - mungkin hanya perlu membaca satu elemen (terutama jika tidak ada predikat). Karena itu, karena sekuens ( IEnumerable<T>) tidak perlu diulang, itu mungkin saja . Any()tanpa predikat pada dasarnya setara dengan foreach(var x in sequence) { return true; } return false;- walaupun menggunakan GetEnumerator()dll alih-alih sintaksis kompiler
Marc Gravell
120
public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable) {
    return enumerable == null || !enumerable.Any();
}
Matt Greer
sumber
8
baik, tidak cukup, OP meminta IEnumerable, bukan IEnumerable <T> ;-)
yoyo
8
Ya, IEnumerabletidak memiliki Any()ekstensi.
Blaise
23

Inilah versi modifikasi dari jawaban bermanfaat @Matt Greer yang menyertakan kelas pembungkus statis sehingga Anda bisa menyalinnya ke file sumber baru, tidak bergantung pada Linq, dan menambahkan generik IEnumerable<T> overload , untuk menghindari tinju tipe nilai itu akan terjadi dengan versi non-generik. [EDIT: Perhatikan bahwa penggunaan IEnumerable<T>tidak mencegah tinju pencacah, pengetikan bebek tidak dapat mencegah hal itu, tetapi setidaknya elemen dalam koleksi yang diketik nilai tidak masing-masing akan dikotakkan.]

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;
    }
}
yoyo
sumber
15

Cara lain adalah dengan mendapatkan Enumerator dan memanggil metode MoveNext () untuk melihat apakah ada item:

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

Ini berfungsi untuk IEnumerable dan juga IEnumerable <T>.

Darren
sumber
4
Haruskah Anda menelepon buang di enumerator ini? Jika koleksi multithreading sadar? Iya. stackoverflow.com/questions/13459447/…
TamusJRoyce
2
@TamusJRoyce Perhatikan bahwa pernyataan Anda hanya berlaku untuk IEnumerable<T>, karena non-generik IEnumerabletidak diterapkan IDisposable.
Ian Kemp
9

Cara saya melakukannya, memanfaatkan beberapa fitur C # modern:

Pilihan 1)

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

Pilihan 2)

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

Dan omong-omong, jangan pernah gunakan Count == 0atau Count() == 0hanya untuk memeriksa apakah koleksi kosong. Selalu gunakan Linq.Any()

Ronald Rey
sumber
2
Hitung == 0 baik-baik saja .... Mungkin lebih cepat daripada Any ()? Namun Anda benar pada Hitungan () == 0 menjadi buruk. Bagi mereka yang bertanya-tanya Count () mengulangi seluruh koleksi Anda, jadi jika itu besar bisa menambah satu ton overhead!
Anthony Nichols
Hitung () hanya mengulangi enumerasi jika tidak dapat dilemparkan ke ICollection. Dengan kata lain, ketika Anda memanggil metode ini, jika sudah ada properti Count pada objek, itu hanya akan mengembalikan itu dan kinerja harus identik. Lihat implementasinya di sini: Referenceource.microsoft.com/#System.Core/System/Linq/…
Ronald Rey
Jika Anda bekerja dengan IEnumerable, menggunakan Count () untuk menguji kekosongan jelas merupakan ide yang buruk karena implementasi Linq AKAN mengulangi seluruh koleksi, sementara Any hanya akan memindahkan iterator satu kali. Ingatlah bahwa Anda tidak dapat menggunakan properti Count dalam kasus ini karena ini bukan bagian dari antarmuka IEnumerable. Itu sebabnya selalu merupakan ide yang lebih baik untuk menggunakan Any () untuk menguji kekosongan dalam semua skenario, menurut pendapat saya.
Ronald Rey
Contoh yang bagus tentang bagaimana operator negasi yang tidak dapat dibaca !, khususnya di opsi kedua;)
Fabio
6

Ini bisa membantu

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;
}
Hossein Narimani Rad
sumber
5

Dimulai dengan C # 6 Anda dapat menggunakan propagasi nol :myList?.Any() == true

Jika Anda masih menemukan ini terlalu tersumbat atau lebih suka metode ekstensi yang baik, saya akan merekomendasikan jawaban Matt Greer dan Marc Gravell, namun dengan sedikit fungsionalitas tambahan untuk kelengkapan.

Jawaban mereka menyediakan fungsionalitas dasar yang sama, tetapi masing-masing dari perspektif lain. Jawaban Matt menggunakan string.IsNullOrEmpty-mentality, sedangkan jawaban Marc mengambil .Any()jalan Linq untuk menyelesaikan pekerjaan.

Saya pribadi cenderung menggunakan .Any()jalan, tetapi ingin menambahkan fungsionalitas pengecekan kondisi dari kelebihan metode lainnya :

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

Jadi Anda masih bisa melakukan hal-hal seperti: myList.AnyNotNull(item=>item.AnswerToLife == 42);seperti yang Anda bisa dengan reguler .Any()tetapi dengan cek nol ditambahkan

Perhatikan bahwa dengan cara C # 6: myList?.Any()mengembalikan a bool?daripada a bool, yang merupakan efek sebenarnya dari propagasi nol

Thomas Mulder
sumber
1
Masalah dengan koleksi? .Any () adalah itu tidak transitif. Ketika nol, koleksi? .Any () == true salah, tetapi koleksi? .Any () == false juga salah. Selain itu
,!
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
}
Scholtz
sumber
2

Berikut kode dari jawaban Marc Gravell , bersama dengan contoh menggunakannya.

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

Seperti yang dia katakan, tidak semua urutan dapat diulang, sehingga kode kadang-kadang dapat menyebabkan masalah, karena IsAny()mulai melangkah melalui urutan. Saya menduga apa maksud jawaban Robert Harvey adalah bahwa Anda sering tidak perlu memeriksa null dan mengosongkan. Seringkali, Anda dapat memeriksa null dan kemudian menggunakannya foreach.

Untuk menghindari memulai urutan dua kali dan memanfaatkan foreach, saya hanya menulis beberapa kode seperti ini:

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

Saya kira metode ekstensi menghemat beberapa baris pengetikan, tetapi kode ini tampaknya lebih jelas bagi saya. Saya menduga bahwa beberapa pengembang tidak akan segera menyadari bahwa IsAny(items)sebenarnya akan mulai melangkah melalui urutan. (Tentu saja jika Anda menggunakan banyak urutan, Anda dengan cepat belajar untuk memikirkan langkah apa yang melaluinya.)

Don Kirkby
sumber
Jika Anda memanggil IsAny dengan nol, itu akan mengeluarkan pengecualian
Ace Trajkov
3
Apakah Anda mencobanya, @Ace? Sepertinya itu akan melempar pengecualian, tetapi metode ekstensi dapat dipanggil pada instance nol .
Don Kirkby
2

Saya menggunakan Bool IsCollectionNullOrEmpty = !(Collection?.Any()??false);. Semoga ini membantu.

Kerusakan:

Collection?.Any()akan kembali nulljika Koleksi adalah nol, dan falsejika Koleksi kosong.

Collection?.Any()??falseakan memberi kita falsejika Koleksi kosong, dan falsejika Koleksi adalah null.

Pelengkap itu akan memberi kita IsEmptyOrNull.

Sabyasachi Mukherjee
sumber
2

Anwser Jon Skeet ( https://stackoverflow.com/a/28904021/8207463 ) memiliki pendekatan yang baik menggunakan Metode Extension - Any () untuk NULL dan KOSONG. TETAPI dia memvalidasi pemilik pertanyaan untuk TIDAK NULL. Jadi hati-hati ubah pendekatan Jon untuk memvalidasi AS NULL ke:

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

JANGAN gunakan (tidak akan divalidasi SEBAGAI NULL):

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

Anda juga dapat dalam kasus memvalidasi SEBAGAI TIDAK NULL (TIDAK diuji hanya sebagai contoh tetapi tanpa kesalahan kompiler) melakukan sesuatu seperti menggunakan predikat:

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

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

Untuk versi .NET yang dapat Anda gunakan, periksa:

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

Adil
sumber
1

Saya memiliki masalah yang sama dan saya menyelesaikannya seperti:

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

"c => c! = null" akan mengabaikan semua entitas nol.

Hosein Djadidi
sumber
1

Saya membangun ini dari jawaban oleh @Matt Greer

Dia menjawab pertanyaan OP dengan sempurna.

Saya menginginkan sesuatu seperti ini sambil mempertahankan kemampuan asli Any sembari memeriksa nol. Saya memposting ini kalau-kalau ada yang membutuhkan sesuatu yang serupa.

Secara khusus saya ingin tetap bisa lulus dalam predikat.

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

Penamaan metode ekstensi mungkin bisa lebih baik.

kb4000
sumber
0

Solusi terbaik lain seperti di bawah ini untuk mengecek kosong atau tidak?

for(var item in listEnumerable)
{
 var count=item.Length;
  if(count>0)
  {
         // not empty or null
   }
  else
  {
       // empty
  }
}
Shakeer Hussain
sumber
1
Itu tidak akan berhasil jika listEnumerablenol, yang merupakan pertanyaan yang ada
Timotei
0

Saya menggunakan ini:

    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) 
}
Jhollman
sumber
0

Karena beberapa sumber daya habis setelah dibaca, saya pikir mengapa tidak menggabungkan cek dan bacaan, alih-alih cek terpisah tradisional, lalu membaca.

Pertama, kami memiliki satu untuk ekstensi inline nol-sederhana yang lebih sederhana:

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

Kemudian kita memiliki sedikit lebih banyak terlibat (well, setidaknya cara saya menulisnya) 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();

Anda tentu saja masih dapat memanggil keduanya tanpa melanjutkan rantai panggilan. Juga, saya menyertakan paramName, sehingga pemanggil dapat menyertakan nama alternatif untuk kesalahan jika tidak "sumber" diperiksa, misalnya "nameof (target)".

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

metode ekstensi saya sendiri untuk memeriksa Tidak null dan Apa pun

NobDev
sumber
0

Tanpa pembantu kustom saya sarankan salah satu ?.Any() ?? falseatau ?.Any() == trueyang relatif singkat dan hanya perlu menentukan urutannya sekali.


Ketika saya ingin memperlakukan koleksi yang hilang seperti yang kosong, saya menggunakan metode ekstensi berikut:

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

Fungsi ini dapat dikombinasikan dengan semua metode LINQ dan foreach, bukan hanya .Any(), itulah sebabnya saya lebih suka daripada fungsi pembantu yang lebih khusus yang diusulkan orang di sini.

CodesInChaos
sumber
0

saya menggunakan

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

Hasilnya akan nol jika tidak cocok, jika tidak mengembalikan salah satu objek

Jika Anda menginginkan daftar tersebut, saya yakin meninggalkan First () atau memanggil ToList () akan memberikan daftar atau nol.

Ron Chibnik
sumber
0

Lihatlah perpustakaan opensource ini: Nzr.ToolBox

public static bool IsEmpty(this System.Collections.IEnumerable enumerable)
Mario Santos
sumber
-1

cukup tambahkan using System.Linqdan lihat keajaiban yang terjadi ketika Anda mencoba mengakses metode yang tersedia di IEnumerable. Menambahkan ini akan memberi Anda akses ke metode bernama Count()sesederhana itu. hanya ingat untuk memeriksa null valuesebelum menelepon count():)

Mohit
sumber
-1

Saya menggunakan sederhana jika untuk memeriksanya

lihat solusi saya

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