2010-08-19 5 views
12

mi sto stancando di usare codice come questo:restituire zero per il conte() su IEnumerables nulli

var count = 0; 
if (myEnumerable != null) 
{ 
    count = myEnumerable.Count(); 
} 

E questo è un po 'saccente:

var count = (myEnumerable ?? new string[0]).Count(); 

C'è un modo più ordinato di facendo questo? Una volta ho avuto un metodo di estensione PhantomCount (mal chiamato) su IEnumerable <> che utilizzava il mio primo esempio di codice, ma aveva un odore particolare (oltre al nome).

risposta

30

Il problema è veramente in tutto ciò che è creazione di questi enumerables. A meno che tu non abbia una buona ragione, qualsiasi cosa che generi una collezione iterabile dovrebbe restituire una collezione vuota invece di null. Questo sarebbe allineato con il Null-Object-Pattern, quindi i benefici sono gli stessi.

Il mio suggerimento sarebbe quello di risolvere qualsiasi produce myEnumerable, o se non è possibile fare questo, aggiungere un controllo modo prima per vedere se è nullo e reagire in modo appropriato.

+12

+1 per diagnosticare la causa principale – cordialgerm

+0

Avere un altro +1. È davvero una buona pratica progettare un'API per restituire le raccolte vuote piuttosto che i null per evitare di gravare sugli sviluppatori affinché eseguano test come questo in ogni momento. – uriDium

+0

Depends. C'è una differenza tra l'elenco di tutti i vini veramente buoni prodotti in Irlanda (che è una lista vuota) e tutti i vini veramente buoni prodotti a Narnia (che è nulla, perché Narnia non esiste). A volte è necessario distinguere null da vuoto. Sono d'accordo sul fatto che uno dovrebbe inclinarsi verso il ritorno vuoto però. –

13

Come su

count = myEnumerable == null? 0 : myEnumerable.Count() 
+1

Ho la sensazione che hes andando a chiedere una più ordinata di questo, uno non di meno :) – VoodooChild

+0

tua sensazione è corretta, ma è una buona risposta in ogni caso. – ProfK

9

Non penso che l'utilizzo del metodo di estensione sia una cattiva idea.

+1

+1 Ho fatto esattamente la stessa cosa - l'ho chiamato "CountOrZero". Personalmente penso che sia più chiaro. –

2

Basta creare il proprio metodo di estensione che gestisca le enumerazioni null come si desidera.

public int CountOrNull<T>(this IEnumerable<T> source) 
{ 
    return source == null ? 0 : source.Count(); 
} 

È quindi possibile utilizzare semplicemente:

var list1 = new int[] { 1, 2, 3, 4 }; 
var list2 = (int[])null; 

var count1 = list1.CountOrNull(); // 4 
var count2 = list2.CountOrNull(); // 0 

Questo è il bello di metodi di estensione. Funzionano ancora bene anche se l'oggetto su cui (sembra che tu sia) chiama il metodo è null.

+0

_ @ Noldorin: _ Corretto un errore di battitura nell'esempio di codice (il commento '// 4'); forse verificare che questo è davvero quello che intendevi. – stakx

+0

@stakx: Grazie; era davvero un errore di battitura. – Noldorin

2

Vorrei scrivere anche il mio metodo di estensione CountOrZeroForNull, come mostrato in altre risposte.

Oltre ... Invece di:

var count = (myEnumerable ?? new string[0]).Count(); 
          // ^^^^^^^^^^^^^ 

si potrebbe scrivere:

var count = (myEnumerable ?? Enumerable.Empty<string>()).Count(); 
          // ^^^^^^^^^^^^^^^^^^^^^^^^^^ 

Ciò non alleviare il tuo problema specifico, ma osteggia assegnazione di una matrice non utilizzato. (Enumerable.Empty<T> è più probabile implementato come un semplice yield break comunicato.)

+0

L'attuale implementazione di 'Enumerable.Empty ' restituisce effettivamente una matrice 'T []' vuota. – LukeH

+0

_ @ LukeH: _ Non ci avrei pensato. Grazie per averlo visto. – stakx

-2
var count = 0; 

if (myEnumerable != null) 
    count = myEnumerable.Count(); 

Anche se non è tecnico come le altre risposte, è di gran lunga il più leggibile.

+2

Non penso che quelle tre righe siano più leggibili di un metodo di estensione ben chiamato. – Lee

+0

Sì, voglio evitare di ripetere più volte lo stesso controllo. Questo era il punto della mia domanda, dopo tutto. – ProfK

+1

Heh, forse leggi la domanda? –

1

Quali azioni intraprendi se il valore restituito è 0?

Se questo è ciò che è interessante, forse si dovrebbe utilizzare il metodo IsNullOrEmpty estensione di Haack per IEnumerable in questo modo:

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

il link è http://haacked.com/archive/2010/06/10/checking-for-empty-enumerations.aspx

Scritto come un commento sul blog, troverete anche un Exception di classe che ho scritto per andare con quel:

public class ArgumentNullOrEmptyException : ArgumentNullException 
{ 
    public ArgumentNullOrEmptyException(string paramName) : base(paramName) 
    {} 

    public ArgumentNullOrEmptyException(string paramName, string message) : base(paramName, message) 
    {} 

    public override string Message 
    { 
     get 
     { 
      return "Value cannot be null nor empty.{0}Parameter name: {1}".FormatWith(Environment.NewLine, ParamName); 
     } 
    } 
} 
5

io uso un extensi personalizzato il metodo:

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

... 

int count = myEnumerable.EmptyIfNull().Count(); 
+0

+1, penso che questo sia il più pulito tra le soluzioni del metodo di estensione elencate. È molto esplicito che si supponga che una null enumerabile sia semplicemente vuota, dopo di che si può lavorare con l'enumerabile come al solito. –