2010-08-19 15 views
12

Me estoy cansando de usar un código como éste:retorno a cero para Count() en IEnumerables nulos

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

Y esto es un poco pedante:

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

¿Hay alguna manera más ordenada de ¿haciendo esto? Una vez tuve un método de extensión PhantomCount (mal nombrado) en IEnumerable <> que usaba mi primer ejemplo de código, pero tenía algo de olor (además del nombre).

Respuesta

30

El problema es realmente en lo que está creando estos enumerables. A menos que tenga una buena razón, cualquier cosa que genere una colección iterable debería devolver una colección vacía en lugar de null. Esto se alinearía con el Null-Object-Pattern, por lo tanto, los beneficios son los mismos.

Mi sugerencia sería la de arreglar lo que produce myEnumerable, o si no puede hacerlo, agregue un control de manera antes para ver si es nulo y reaccionan de forma adecuada.

+12

+1 para diagnosticar la causa raíz – cordialgerm

+0

Tener otro +1. Es una buena práctica cuando se diseña una API devolver colecciones vacías en lugar de nulos para evitar poner una carga en los desarrolladores para hacer pruebas como esta todo el tiempo. – uriDium

+0

Depende. Hay una diferencia entre la lista de todos los vinos realmente buenos hechos en Irlanda (que es una lista vacía) y todos los vinos realmente buenos hechos en Narnia (que es nulo, porque Narnia no existe). A veces es necesario distinguir nulo de vacío. Sin embargo, estoy de acuerdo en que uno debe inclinarse hacia el vacío. –

13

¿Qué tal

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

Tengo la sensación de que hes que van a pedir una más ordenado que esto, no es menos 1 :) – VoodooChild

+0

Su sentimiento es correcto, pero es una buena respuesta de todos modos. – ProfK

9

No creo que usar el método de extensión sea una mala idea.

public static int NullableCount<T>(this IEnumerable<T> collection) 
{ 
    return collection == null ? 0 : collection.Count(); 
} 
+1

+1 Hice exactamente lo mismo, simplemente lo llamé 'CountOrZero'. Personalmente creo que es más claro. –

2

Simplemente crea tu propio método de extensión que maneje enumeradores nulos como desees.

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

continuación, puede simplemente usar:

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

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

Esa es la gran cosa acerca de los métodos de extensión. Todavía funcionan bien incluso si el objeto sobre el que llama (al parecer) llama al null.

+0

_ @ Noldorin: _ Se corrigió un error tipográfico en el ejemplo del código (el comentario '// 4'); tal vez verificar que esto es de hecho lo que pretendía. – stakx

+0

@stakx: Gracias; fue de hecho un error tipográfico. – Noldorin

2

También escribiría mi propio método de extensión CountOrZeroForNull, como se muestra en otras respuestas.

Además ... En lugar de:

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

se podría escribir:

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

Esto no soluciona su problema específico, pero elude la asignación de una matriz sin utilizar. (Enumerable.Empty<T> es más probable implementarse como un simple yield break comunicado.)

+0

La implementación actual de 'Enumerable.Empty ' en realidad devuelve una matriz singleton vacía 'T []'. – LukeH

+0

_ @ LukeH: _ No lo hubiera pensado. Gracias por mirar esto. – stakx

-2
var count = 0; 

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

Si bien no es tan técnico como las otras respuestas, es mucho más fácil de leer.

+2

No creo que esas tres líneas sean más legibles que un método de extensión bien nombrado. – Lee

+0

Sí, quiero evitar repetir el mismo cheque varias veces. Ese era el punto de mi pregunta después de todo. – ProfK

+1

Heh, ¿quizás leyó la pregunta? –

1

¿Qué medidas está tomando si el valor devuelto es 0?

Si eso es lo interesante, tal vez usted debe usar el método IsNullOrEmpty extensión de Haack para IEnumerable así:

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

El enlace es http://haacked.com/archive/2010/06/10/checking-for-empty-enumerations.aspx

publicado como un comentario en el blog, también encontrará una clase Exception escribí para ir con eso:

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

Puedo utilizar una extensi personalizada en el método:

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

... 

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

+1, creo que esta es la más limpia de las soluciones de método de extensión enumeradas. Es muy explícito que está asumiendo que un enumerable nulo simplemente está vacío, después de lo cual puede trabajar con el enumerable como de costumbre. –