En C # uso LINQ e IEnumerable un poco. Y todo está bien y bien (o al menos en su mayor parte).
Sin embargo, en muchos casos me encuentro que necesito un vacío IEnumerable<X>
por defecto. Es decir, me gustaria
for (var x in xs) { ... }
para trabajar sin necesidad de una verificación nula. Ahora, esto es lo que hago actualmente, dependiendo del contexto más amplio:
var xs = f() ?? new X[0]; // when xs is assigned, sometimes
for (var x in xs ?? new X[0]) { ... } // inline, sometimes
Ahora, aunque lo anterior está perfectamente bien para mí , es decir, si hay alguna "sobrecarga adicional" con la creación del objeto de matriz, simplemente no me importa , me preguntaba:
¿Hay singleton "IEnumerable / IList inmutable vacío" en C # /. NET? (E, incluso si no es así, ¿existe una forma "mejor" de manejar el caso descrito anteriormente?)
Java tiene Collections.EMPTY_LIST
singleton inmutable - "bien escrito" vía Collections.emptyList<T>()
- que sirve para este propósito, aunque no estoy seguro de si un concepto similar podría funcionar en C # porque los genéricos se manejan de manera diferente.
Gracias.
public static class Array<T> { public static readonly T[] Empty = new T[0]; }
y se le puede llamar como:Array<string>.Empty
. Pregunté al respecto aquí en CodeReview .Respuestas:
Que está buscando
Enumerable.Empty<T>()
.En otras noticias, la lista vacía de Java apesta porque la interfaz List expone métodos para agregar elementos a la lista que arrojan excepciones.
fuente
List
(una colección a la que se puede acceder por índice). EsosList
pueden ser de solo lectura. Y en algún momento debe devolver un solo lecturaList
con un elemento cero. Así, elCollections.emptyList()
método. No puede simplemente devolver un Iterable vacío porque una interfaz implementada especifica que el método devuelve una lista. El gran problema es que no hay una interfaz ImmutableList que pueda devolver. El mismo problema existe en .NET: cualquieraIList
puede ser de solo lectura.Enumerable.Empty<T>()
es exactamente eso.fuente
Array.Empty<T>()
es más precisa, ya que es unIList<T>
. Tiene la feliz ventaja de ser también satisfactorioIReadOnlyCollection<T>
. Por supuesto, dondeIEnumerable<T>
sí es suficiente,Enumerable.Empty<T>()
encaja perfectamente.Array.Empty<T>
estuviera disponible. :) En cualquier caso, a pesar del título, la pregunta deja explícitamente claro que unIEnumerable<T>
es bueno para el propósito.Creo que estás buscando
Enumerable.Empty<T>()
.Singleton de lista vacía no tiene mucho sentido, porque las listas a menudo son mutables.
fuente
En su ejemplo original, usa una matriz vacía para proporcionar un enumerable vacío. Si bien usar
Enumerable.Empty<T>()
es perfectamente correcto, puede haber otros casos: si tiene que usar una matriz (o laIList<T>
interfaz), puede usar el métodolo que le ayuda a evitar asignaciones innecesarias.
Notas / referencias:
fuente
Creo que agregar un método de extensión es una alternativa limpia gracias a su capacidad para manejar nulos, algo como:
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> list) { return list ?? Enumerable.Empty<T>(); } foreach(var x in xs.EmptyIfNull()) { ... }
fuente
Microsoft implementó 'Any ()' así ( fuente )
public static bool Any<TSource>(this IEnumerable<TSource> source) { if (source == null) throw new ArgumentNullException("source"); using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return true; } return false; }
Si desea guardar una llamada en la pila de llamadas, en lugar de escribir un método de extensión que llame
!Any()
, simplemente vuelva a escribir y realice estos tres cambios:public static bool IsEmpty<TSource>(this IEnumerable<TSource> source) //first change (name) { if (source == null) throw new ArgumentNullException("source"); using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return false; //second change } return true; //third change }
fuente
Usar
Enumerable.Empty<T>()
con listas tiene un inconveniente. Si realiza la manoEnumerable.Empty<T>
en el constructor de la lista, se asigna una matriz de tamaño 4. Pero si entrega un vacíoCollection
en el constructor de la lista, no se produce ninguna asignación. Entonces, si usa esta solución en todo su código, lo más probable es que uno de losIEnumerable
s se use para construir una lista, lo que resultará en asignaciones innecesarias.fuente