example .net linq ienumerable

.net - example - IEnumerable está vacío?



ienumerable c# example (9)

Desea el método de extensión IEnumerable.Any() (.Net Framework 3.5 y superior). Evita contar sobre los elementos.

Sé que probablemente no importa / afecta el rendimiento en su mayor parte, pero odio la idea de obtener un IEnumerable y hacer .Count() . ¿Hay un IsEmpty o NotEmpty o alguna función? (similar a stl empty ())


En IEnumerable o IEnumerable<T> , no.

Pero realmente no tiene mucho sentido. Si una colección está vacía e intenta iterar sobre ella utilizando IEnumerable , la llamada a IEnumerator.MoveNext() simplemente devolverá false sin costo de rendimiento.


No lo creo, para eso está el Count . Además, ¿qué será más rápido?

  1. Acceder a una propiedad y recuperar un Integer almacenado
  2. Acceder a una propiedad y recuperar un Boolean almacenado

Puede usar métodos de extensión como Any () o Count (). Count () es más costoso que Any (), ya que debe ejecutar toda la enumeración, como han señalado otros.

Pero en el caso de la evaluación perezosa (por ejemplo, un método que utiliza el rendimiento), cualquiera puede ser costoso. Por ejemplo, con la siguiente implementación de IEnumerable , cada llamada a Any o Count incurrirá en el costo de una nueva ida y vuelta a la base de datos:

IEnumerable<MyObject> GetMyObjects(...) { using(IDbConnection connection = ...) { using(IDataReader reader = ...) { while(reader.Read()) { yield return GetMyObjectFromReader(reader); } } } }

Creo que la moraleja es:

  • Si solo tiene un IEnumerable<T> , y desea hacer algo más que enumerarlo (por ejemplo, use Count o Any), considere la posibilidad de convertirlo primero en una lista (método de extensión ToList). De esta forma, garantiza que solo enumerará una vez.

  • Si está diseñando una API que devuelve una colección, considere devolver ICollection<T> (o incluso IList<T> ) en lugar de IEnumerable<T> como muchas personas parecen recomendar. Al hacerlo, está fortaleciendo su contrato para garantizar que no haya evaluación diferida (y, por lo tanto, no hay una evaluación múltiple).

Tenga en cuenta que estoy diciendo que debería considerar devolver una colección, no siempre devolver una colección. Como siempre, hay compensaciones, como se puede ver en los comentarios a continuación.

  • @KeithS cree que nunca deberías rendir en un DataReader, y aunque nunca digo nunca, diría que, en general, es un buen consejo que una capa de acceso a datos devuelva un ICollection<T> lugar de un IEnumerable<T> evaluado de forma IEnumerable<T> para las razones que KeithS da en su comentario.

  • @Bear Monkey señala que la creación de instancias de una lista puede ser costosa en el ejemplo anterior si la base de datos devuelve una gran cantidad de registros. Eso también es cierto, y en algunos casos (probablemente excepcionales) puede ser apropiado ignorar el consejo de @ KeithS y devolver una enumeración evaluada de forma diferida, siempre que el consumidor esté haciendo algo que no consuma demasiado tiempo (por ejemplo, generar algunos valores agregados).


Sin necesidad de LINQ, puede hacer lo siguiente:

bool IsEmpty(IEnumerable en) { foreach(var c in en) { return false; } return true; }


También puede escribir sus propias sobrecargas de método de extensión Count así:

/// <summary> /// Count is at least the minimum specified. /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="min"></param> /// <returns></returns> public static bool Count<TSource>(this IEnumerable<TSource> source, int min) { if (source == null) { throw new ArgumentNullException("source"); } return source.Count(min, int.MaxValue); } /// <summary> /// Count is between the given min and max values /// </summary> /// <typeparam name="TSource"></typeparam> /// <param name="source"></param> /// <param name="min"></param> /// <param name="max"></param> /// <returns></returns> public static bool Count<TSource>(this IEnumerable<TSource> source, int min, int max) { if (source == null) { throw new ArgumentNullException("source"); } if (min <= 0) { throw new ArgumentOutOfRangeException("min", "min must be a non-zero positive number"); } if (max <= 0) { throw new ArgumentOutOfRangeException("max", "max must be a non-zero positive number"); } if (min >= max) throw new ArgumentOutOfRangeException("min and max", "min must be lest than max"); var isCollection = source as ICollection<TSource>; if (isCollection != null) return isCollection.Count >= min && isCollection.Count <= max; var count = 0; using (var enumerator = source.GetEnumerator()) { while (enumerator.MoveNext()) { count++; if (count >= min && count <= max) return true; } } return false; }


Tenga en cuenta que IEnumerable es solo una interfaz. La implementación detrás de esto puede ser muy diferente de una clase a otra (considere el ejemplo de Joe). El método de extensión IEnumerable.Any () tiene que ser un enfoque genérico y puede no ser lo que desea (en cuanto al rendimiento). Yossarian sugiere un medio que debería funcionar para muchas clases, pero si la implementación subyacente no utiliza ''rendimiento'', aún podría pagar un precio.

En general, si se apega a colecciones o matrices envueltas en una interfaz IEnumerable, entonces Cristobalito y Yossarian probablemente tengan las mejores respuestas. Mi suposición es que el método integrado .Any () ext hace lo que recomienda Yossarian.


Use Enumerable.Empty () que en lugar de IEnumerable.Any () evitará que termine teniendo una lista nula.


si no es genérico que algo así

enumeration.Cast<object>().Any();

si es genérico, usa la extensión de Enumerable como ya se dijo