explained c# ienumerable

explained - ienumerator c#



¿Debo siempre devolver IEnumerable<T> en lugar de IList<T>? (13)

Cuando estoy escribiendo mi DAL u otro código que devuelve un conjunto de elementos, siempre debo hacer mi declaración de devolución:

public IEnumerable<FooBar> GetRecentItems()

o

public IList<FooBar> GetRecentItems()

Actualmente, en mi código he intentado usar IEnumerable tanto como sea posible, pero no estoy seguro de si esto es una buena práctica. Parecía correcto porque estaba devolviendo el tipo de datos más genérico sin dejar de ser descriptivo de lo que hace, pero quizás esto no es correcto.


Creo que puedes usar cualquiera de los dos, pero cada uno tiene un uso. Básicamente List es IEnumerable pero tiene funcionalidad count, add element, remove element

IEnumerable no es eficiente para contar elementos

Si la colección está destinada a ser de solo lectura, o la modificación de la colección está controlada por el Parent entonces devolver un IList solo por Count no es una buena idea.

En Linq, hay un método de extensión Count() en IEnumerable<T> que dentro del CLR IEnumerable<T> a .Count si el tipo subyacente es de IList , por lo que la diferencia de rendimiento es insignificante.

En general, creo (opinión) que es mejor devolver IEnumerable donde sea posible, si necesita hacer adiciones, agregue estos métodos a la clase principal, de lo contrario el consumidor administrará la colección dentro del Modelo que infringe los principios, por ejemplo, el manufacturer.Models.Add(model) Modelos manufacturer.Models.Add(model) viola la ley de demeter. Por supuesto, estas son solo pautas y no reglas duras y rápidas, pero hasta que no tenga plena comprensión de la aplicabilidad, seguirlo a ciegas es mejor que no seguirlo en absoluto.

public interface IManufacturer { IEnumerable<Model> Models {get;} void AddModel(Model model); }

(Nota: si usa nNHibernate, es posible que deba asignar un IList privado usando diferentes accesadores).


Como todos han dicho que depende, si no quieres agregar / quitar la funcionalidad en la capa de llamadas, votaré por IEnumerable, ya que solo proporciona la iteración y la funcionalidad básica que, en diseño, prefiero. Al regresar a IList mis votos siempre son de nuevo, pero es principalmente lo que te gusta y lo que no. en términos de rendimiento, creo que son más de lo mismo.


Creo que la regla general es usar la clase más específica para devolver, para evitar hacer un trabajo innecesario y darle a quien llama más opciones.

Dicho esto, creo que es más importante considerar el código que está escribiendo que el que escribirá el siguiente tipo (dentro de lo razonable). Esto se debe a que puede hacer suposiciones sobre el código que ya existe.

Recuerde que mover UP a una colección desde IEnumerable en una interfaz funcionará, moviéndose hacia abajo a IEnumerable desde una colección se romperá el código existente.

Si todas estas opiniones parecen estar en conflicto, es porque la decisión es subjetiva.


Creo que puedes usar cualquiera de los dos, pero cada uno tiene un uso. Básicamente List es IEnumerable pero tiene funcionalidad count, Add element, remove element

IEnumerable no es eficiente para contar elementos u obtener un elemento específico en la colección.

List es una colección que es ideal para encontrar elementos específicos, elementos fáciles de agregar o eliminarlos.

En general, trato de usar la List siempre que sea posible, ya que esto me da más flexibilidad.

Use List<FooBar> getRecentItems() lugar de IList<FooBar> GetRecentItems()


En general, debe solicitar el más genérico y devolver lo más específico que pueda. Entonces, si tienes un método que toma un parámetro, y realmente solo necesitas lo que está disponible en IEnumerable, entonces ese debería ser tu tipo de parámetro. Si su método puede devolver un IList o un IEnumerable, prefiera devolver IList. Esto asegura que pueda ser utilizado por la más amplia gama de consumidores.

Sea flexible en lo que necesita y explícito en lo que proporciona.


Eso depende...

Devolver el tipo menos derivado ( IEnumerable ) le dejará la mayor libertad para cambiar la implementación subyacente en la pista.

La devolución de un tipo más derivado ( IList ) proporciona a los usuarios de su API más operaciones sobre el resultado.

Siempre sugeriría devolver el tipo menos derivado que tenga todas las operaciones que sus usuarios necesitarán ... así que básicamente, primero tiene que eliminar las operaciones en el resultado que tienen sentido en el contexto de la API que está definiendo.


Las pautas de diseño del marco recomiendan usar la Collection la clase cuando necesite devolver una colección que pueda ser modificada por la persona que llama o ReadOnlyCollection para las colecciones de solo lectura.

La razón por la cual esto es preferible a un IList simple es que IList no informa a la persona que llama si es solo de lectura o no.

Si devuelve un IEnumerable<T> lugar, ciertas operaciones pueden ser un poco más complicadas de realizar para la persona que llama. Además, ya no le dará flexibilidad a la persona que llama para modificar la colección, algo que puede o no desear.

Tenga en cuenta que LINQ contiene algunos trucos bajo su manga y optimizará ciertas llamadas según el tipo en que se ejecutan. Entonces, por ejemplo, si realiza un conteo y la colección subyacente es una lista, NO recorrerá todos los elementos.

Personalmente, para un ORM, probablemente me quedo con Collection<T> como valor de retorno.


No es tan simple cuando se habla de valores de retorno en lugar de parámetros de entrada. Cuando se trata de un parámetro de entrada, sabes exactamente lo que tienes que hacer. Entonces, si necesita poder iterar sobre la colección, toma un IEnumberable, mientras que si necesita agregar o eliminar, toma un IList.

En el caso de un valor de retorno, es más difícil. ¿Qué espera tu interlocutor? Si devuelves un IEnumerable, entonces él no sabrá a priori que puede hacer un IList fuera de él. Pero, si devuelve un IList, sabrá que puede repetirlo. Por lo tanto, debe tener en cuenta lo que la persona que llama va a hacer con los datos. La funcionalidad que su interlocutor necesita / espera es lo que debe gobernar al tomar una decisión sobre qué devolver.


Podría estar un poco mal aquí, dado que nadie más lo sugirió hasta ahora, pero ¿por qué no devuelves una (I)Collection<T> ?

Por lo que recuerdo, Collection<T> fue el tipo de devolución preferido sobre List<T> porque abstrae la implementación. Todos implementan IEnumerable , pero eso me suena demasiado bajo para el trabajo.


Realmente depende de por qué estás usando esa interfaz específica.

Por ejemplo, IList<T> tiene varios métodos que no están presentes en IEnumerable<T> :

  • IndexOf(T item)
  • Insert(int index, T item)
  • RemoveAt(int index)

y Propiedades:

  • T this[int index] { get; set; }

Si necesita estos métodos de alguna forma, devuelva IList<T> .

Además, si el método que consume su resultado de IEnumerable<T> espera un IList<T> , se evitará que el CLR considere las conversiones necesarias, optimizando así el código compilado.


Si no cuenta en su código externo, siempre es mejor devolver IEnumerable, porque más tarde puede cambiar su implementación (sin impacto de código externo), por ejemplo, para lógica iterativa de rendimiento y conservar recursos de memoria (muy buena característica de idioma por cierto) )

Sin embargo, si necesita contar los elementos, no olvide que hay otra capa entre IEnumerable e IList - ICollection .


Una cosa a tener en cuenta es que si está utilizando una instrucción LINQ de ejecución diferida para generar su IEnumerable<T> , llamar a .ToList() antes de regresar de su método significa que sus elementos se pueden iterar dos veces: una para crear la Lista , y una vez cuando la persona que llama pasa, filtra o transforma su valor de retorno. Cuando sea práctico, me gustaría evitar convertir los resultados de LINQ-to-Objects a una Lista concreta o Diccionario hasta que tenga que hacerlo. Si mi interlocutor necesita una lista, es una forma sencilla de llamar. No tengo que tomar esa decisión por ellos, y eso hace que mi código sea un poco más eficiente en los casos en que la persona que llama simplemente está haciendo un foreach.


List<T> ofrece muchas más características al código de llamada, como la modificación del objeto devuelto y el acceso por índice. Entonces, la pregunta se reduce a: en el caso de uso específico de su aplicación, ¿QUIERE apoyar tales usos (presumiblemente devolviendo una colección recién construida) para la conveniencia de la persona que llama, o quiere velocidad para el caso simple cuando todo el la persona que llama necesita recorrer la colección y puede devolver de manera segura una referencia a una colección subyacente real sin temor a que esto la cambie erróneamente, etc.

Solo usted puede responder a esta pregunta, y solo entendiendo bien lo que sus interlocutores querrán hacer con el valor de retorno, y qué tan importante es el rendimiento aquí (qué tan grande son las colecciones que estaría copiando, qué tan probable es que esto sea un cuello de botella, etc.)