Cuando escribo mi DAL u otro código que devuelve un conjunto de elementos, ¿debo siempre 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 esta es la mejor 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 tal vez esto no sea correcto.
c#
ienumerable
ReyNestor
fuente
fuente
Respuestas:
Realmente depende de por qué está utilizando esa interfaz específica.
Por ejemplo,
IList<T>
tiene varios métodos que no están presentes enIEnumerable<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 manera, entonces regrese
IList<T>
.Además, si el método que consume suIEnumerable<T>
resultado espera un resultadoIList<T>
, evitará que CLR considere las conversiones necesarias, optimizando así el código compilado.fuente
Las pautas de diseño de framework recomiendan usar la colección de clases cuando necesitas devolver una colección que el llamador puede modificar o ReadOnlyCollection para colecciones de solo lectura.
La razón por la que se prefiere esto a una simple
IList
es queIList
no informa a la persona que llama si es de solo lectura o no.Si devuelve un
IEnumerable<T>
en su lugar, ciertas operaciones pueden ser un poco más complicadas para la persona que llama. Además, ya no le dará a la persona que llama la flexibilidad de modificar la colección, algo que puede que desee o no.Tenga en cuenta que LINQ contiene algunos trucos bajo la manga y optimizará ciertas llamadas según el tipo en el que se realizan. Entonces, por ejemplo, si realiza una
Count
y la colección subyacente es una Lista, NO recorrerá todos los elementos.Personalmente, para un ORM probablemente me quedaría
Collection<T>
como mi valor de retorno.fuente
En general, debe solicitar lo más genérico y devolver lo más específico que pueda. Entonces, si tiene un método que toma un parámetro, y solo necesita lo que está disponible en IEnumerable, entonces ese debería ser su tipo de parámetro. Si su método puede devolver un IList o un IEnumerable, prefiera devolver IList. Esto asegura que sea utilizable por la más amplia gama de consumidores.
Sea flexible en lo que necesita y explícito en lo que proporciona.
fuente
Eso depende...
Devolver el tipo menos derivado (
IEnumerable
) le dejará el mayor margen de maniobra para cambiar la implementación subyacente en el futuro.Devolver 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 van a necesitar ... así que, básicamente, primero debe eliminar las operaciones en el resultado que tienen sentido en el contexto de la API que está definiendo.
fuente
Una cosa a considerar es que si está utilizando una declaración LINQ de ejecución diferida para generar su
IEnumerable<T>
, llamar.ToList()
antes de regresar desde su método significa que sus elementos pueden repetirse dos veces: una vez para crear la Lista y una vez cuando la persona que llama se repite. , filtra o transforma su valor de retorno. Cuando sea práctico, me gusta evitar convertir los resultados de LINQ-to-Objects en una Lista o Diccionario concreto hasta que sea necesario. Si la persona que llama necesita una lista, es una simple llamada de método fácil; no necesito 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 solo está haciendo un foreach.fuente
List<T>
ofrece al código de llamada muchas más funciones, como modificar el objeto devuelto y acceder por índice. Entonces, la pregunta se reduce a: en el caso de uso específico de su aplicación, ¿DESEA admitir dichos usos (¡presumiblemente devolviendo una colección recién construida!), Para la conveniencia de la persona que llama, o desea velocidad para el caso simple cuando todos los lo que necesita la persona que llama es recorrer la colección y puede devolver de forma segura una referencia a una colección subyacente real sin temer que esto la cambie por error, etc.Solo usted puede responder esta pregunta, y solo si comprende bien lo que las personas que llaman querrán hacer con el valor de retorno y qué tan importante es el rendimiento aquí (qué tan grandes son las colecciones que estaría copiando, qué tan probable es que esto sea un cuello de botella, etc).
fuente
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 unIList
solo paraCount
no es una buena idea.En Linq, hay un
Count()
método de extensión en elIEnumerable<T>
que dentro del CLR se accederá a.Count
si el tipo subyacente es deIList
, por lo que la diferencia de rendimiento es insignificante.En general, creo (opinión) que es una mejor práctica devolver IEnumerable donde sea posible, si necesita hacer adiciones, agregue estos métodos a la clase principal; de lo contrario, el consumidor administra la colección dentro del Modelo que viola los principios, por ejemplo,
manufacturer.Models.Add(model)
viola la ley de demeter. Por supuesto, estas son solo pautas y no reglas estrictas y rápidas, pero hasta que tenga una comprensión completa de la aplicabilidad, es mejor seguir ciegamente que no seguir en absoluto.(Nota: si usa nNHibernate, es posible que deba mapear a IList privada usando diferentes accesadores).
fuente
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, sabe exactamente lo que debe 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 la persona que llama? Si devuelve un IEnumerable, entonces él no sabrá a priori que puede convertirlo en un IList. Pero, si devuelve un IList, sabrá que puede iterar sobre él. Por lo tanto, debe tener en cuenta lo que hará la persona que llama con los datos. La funcionalidad que la persona que llama necesita / espera es lo que debe regir al tomar la decisión sobre qué devolver.
fuente
como todos han dicho, depende, si no desea Agregar / Eliminar funcionalidad en la capa de llamada, votaré por IEnumerable, ya que solo proporciona iteración y funcionalidad básica que, en perspectiva de diseño, me gusta. Volviendo 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.
fuente
Si no cuenta en su código externo, siempre es mejor devolver IEnumerable, porque luego puede cambiar su implementación (sin impacto de código externo), por ejemplo, para generar lógica de iterador y conservar recursos de memoria (muy buena característica de lenguaje por cierto ).
Sin embargo, si necesita un recuento de elementos, no olvide que hay otra capa entre IEnumerable e IList - ICollection .
fuente
Puede que esté un poco fuera de lugar, ya que nadie más lo sugirió hasta ahora, pero ¿por qué no devuelves un
(I)Collection<T>
?Por lo que recuerdo,
Collection<T>
fue el tipo de retorno preferidoList<T>
porque abstrae la implementación. Todos implementanIEnumerable
, pero eso me suena un poco demasiado bajo para el trabajo.fuente
Creo que puedes usar cualquiera, pero cada uno tiene un uso. Básicamente lo
List
es,IEnumerable
pero tiene la funcionalidad de conteo, agregar elemento, eliminar elementoIEnumerable
no es eficiente para contar elementos o para obtener un elemento específico en la colección.List
es una colección ideal para encontrar elementos específicos, fácil de agregar o eliminar.En general, trato de usarlo
List
siempre que sea posible, ya que esto me da más flexibilidad.Usar en
List<FooBar> getRecentItems()
lugar deIList<FooBar> GetRecentItems()
fuente
Creo que la regla general es usar la clase más específica para regresar, para evitar hacer trabajos innecesarios y darle más opciones a la persona que llama.
Dicho esto, creo que es más importante considerar el código que está escribiendo frente a usted que el código que escribirá el próximo (dentro de lo razonable). Esto se debe a que puede hacer suposiciones sobre el código que ya existe.
Recuerde que moverse hacia ARRIBA a una colección desde IEnumerable en una interfaz funcionará, moverse hacia abajo a IEnumerable desde una colección romperá el código existente.
Si todas estas opiniones parecen estar en conflicto, es porque la decisión es subjetiva.
fuente
TL; DR; - resumen
List
) para los valores de retorno y el tipo más genérico para los parámetros de entrada, incluso en el caso de colecciones.IReadOnlyList
oIReadOnlyCollection
como el tipo de valor de retorno.Más
fuente