2011-11-09 18 views
8

Se voglio eseguire azioni come .Dove (...) o .max (...), ho bisogno di assicurarsi che la lista non è nullo ed ha un conteggio maggiore di zero. Oltre a fare qualcosa come il seguente ogni volta che voglio utilizzare l'elenco:Un modo migliore per verificare la presenza di elementi nell'elenco?

if(mylist != null && mylist.Count > 0) 
{...} 

c'è qualcosa di più in linea o lambda come tecnica che posso usare? O un'altra tecnica più compressa?

+5

IMHO, oggetti come un elenco non devono mai essere nulli. Inizialmente li inizializzo se sono membri della classe e, se vengono restituiti da una funzione della mia creazione, mi assicuro che la funzione restituisca una lista vuota anziché null. –

+0

Possibile duplicato della risposta all'indirizzo: http://stackoverflow.com/questions/41319/checking-if-a-list-is-empty-with-linq – VS1

+0

È sempre possibile scrivere i propri metodi di estensione per utilizzare le azioni come Where() o Max() che includeranno il test Null e Count prima di utilizzare il metodo di estensione effettivo. – Paul

risposta

3

La mia preferenza generale è quello di avere le istanze elenco vuoto, invece di variabili di lista nulli. Tuttavia, non tutti possono convincere i loro collaboratori a questo accordo. È possibile proteggersi da variabili di lista nulle utilizzando questo metodo di estensione.

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

Chiamato da:

Customers result = myList.EmptyIfNull().Where(c => c.Name == "Bob"); 

maggior parte dei metodi di LINQ lavorano su collezioni vuote. Due metodi che non sono Min e Max. Generalmente, chiamo questi metodi contro un IGrouping. La maggior parte delle implementazioni di IGrouping ha almeno un elemento (ad esempio, IGroupings generati da GroupBy o ToLookup). Per altri casi, è possibile utilizzare Enumerable.DefaultIfEmpty.

int result = myList.EmptyIfNull().Select(c => c.FavoriteNumber).DefaultIfEmpty().Max(); 
1

Si potrebbe provare myList.Any() invece di .Count, ma si sarebbe ancora bisogno di verificare la presenza di null.

+0

Giusto, quindi avresti ancora bisogno di verificare la presenza di null. – Igor

2

Non lasciate che la lista sia nulla

verificare che l'oggetto è sempre in uno stato valido. Assicurandosi che l'elenco non sia mai nullo, non è mai necessario verificare che l'elenco sia nullo.

public class MyClass 
{ 
    private readonly IEnumerable<int> ints; 

    public MyClass(IEnumerable<int> ints) 
    { 
     this.ints = ints; 
    } 

    public IEnumerable<int> IntsGreaterThan5() 
    { 
     return this.ints.Where(x => x > 5); 
    } 
} 

Anche se questo elenco fosse vuoto, si otterrebbe comunque uno IEnumerable<int> valido.

Max e Min Sovraccarichi con i tipi Nullable

Che ancora non risolve il "Max" e problemi "min" però. C'è un sovraccarico di Max e Min che prendono i selettori. Quelle sovraccarichi selettore può tornare int nullable, quindi il metodo di massima diventa questo:

this.ints.Max(x => new int?(x)); 

Pertanto, si esegue Max e controllare per vedere se hai ottenuto un valore nullo o un intero indietro. Ecco!

Altre opzioni

Metodi di estensione personalizzata

si potrebbe anche scrivere i propri metodi di estensione.

public static MinMaxHelper() 
{ 
    public static int? MaxOrDefault(IEnumerable<int> ints) 
    { 
     if(!ints.Any()) 
     { 
      return null; 
     } 

     return ints.Max(); 
    } 

    public static int MaxOrDefault(IEnumerable<int> ints, int defaultValue) 
    { 
     if(!ints.Any()) 
     { 
      return defaultValue; 
     } 

     return ints.Max(); 
    } 
} 

Override Linq Metodi di estensione

E Infine, ricordate che la configurazione in metodi di estensione LINQ può essere sovrascritto con i propri metodi di estensione con firme di corrispondenza. Pertanto, è possibile scrivere un metodo di estensione per sostituire .Where (...) e .Max (...) per restituire null (o un valore predefinito) invece di generare un'eccezione ArgumentNullException se Enumerable è null.

+2

stai rispondendo a questa domanda? – Snowbear

+0

Scusa, devo aver avuto una brutta giornata. Ho visto molte verifiche nulle e liste di istanze all'interno di cicli while e così ultimamente, invece di istanziare semplicemente l'elenco con la classe. –

1

Se c'è il rischio della vostra lista essere nullo si alway controlla che prima di chiamare uno qualsiasi dei suoi metodi, ma è possibile utilizzare il metodo Qualsiasi(), piuttosto che contare. Questo restituirà true non appena conta un oggetto, indipendentemente dal fatto che ci sia uno o più elementi nell'elenco. Ciò consente di risparmiare l'iterazione su tutta la lista che è quello che Conte farà:

if(mylist != null && mylist.Any()) 
{...} 
9
public static class LinqExtensions 
{ 
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) 
    { 
      return items == null || !items.Any(); 
    } 
} 

È quindi possibile fare qualcosa di simile

if (!myList.IsNullOrEmpty()) 
.... 
+0

Quale condizione fa '! Items.Any(); '? – sll

+0

@sll, no, Any() genererà un'eccezione ArgumentNullException se l'origine è nullo. –

+1

non verrà mai eseguito perché prima di 'item == null' check ... – sll

2

Usa empty collezioni invece di null collezioni.Where funzionerà bene contro una raccolta vuota, quindi non è necessario garantire che Count > 0 prima di chiamarlo. Puoi anche chiamare Max su una raccolta vuota se prima fai un bit of gymnastics.

Per IEnumerable<T> uso Enumerable.Empty<T>()

Per T[] uso new T[0]

Per List<T> uso new List<T>()

1

È possibile utilizzare ?? operatore che converte nullo al valore fornite sul lato destro:

public ProcessList(IEnumerable<int> ints) 
{ 
    this.ints = ints ?? new List<int>(); 
} 

proposito: Non è un problema per elaborare un elenco vuoto utilizzando LINQ.

1

Non è necessario controllare Count per chiamare Where. Max ha bisogno di una lista non vuota per i tipi di valore, ma che può essere superato con un cast in linea, ad esempio

int? max = new List<int>().Max(i => (int?)i); // max = null 
Problemi correlati