2009-03-25 8 views
8

Imagine que tengo una capa de SearchService que tiene un método para buscar todos los automóviles comenzando con una cierta cadena;¿Qué interfaz debería devolver mi servicio? IQueryable, IList, IEnumerable?

public static class Searcher{ 
    public IAnInterface<Car> CarsStartingWith(string startWith){ 
     //magic 
    } 
} 

¿Qué interfaz debe usar mi servicio?
IQueryable puede representar una interfaz fluida en el resto de mi aplicación.
IEnumerable tiene el aspecto perezoso que conlleva.
IList es simplemente el más práctico.

me gustaría tener a todos mis servicios de devolución de la misma interfaz para la consistencia hace que todo sea mucho más fácil.
ICollection tal vez podría ser una opción también, pero sólo ofrece tan poco ...

+0

Discusión casi duplicada aquí: http://stackoverflow.com/questions/396513/should-parameters-returns-of-collections-be-ienumerablet-or-t –

Respuesta

2

si desea que todos sus servicios para devolver la misma interfaz entonces probablemente vaya para IEnumerable<>.

Va a ser bastante fácil para las personas que llaman para convertir a IQueryable o crean un List, si es necesario:

IEnumerable<Car> cars = Searcher.CarsStartingWith("L"); 
var carsList = cars.ToList(); 
var queryableCars = cars.AsQueryable(); 
+0

Totalmente de acuerdo. Siempre debe usar el contrato mínimo que se requiere. IEnumerable puede ser consumido o convertido por muchos tipos de BCL, como lo ha demostrado. –

+0

Es cierto. Decidí devolver IEnumerable. Y si un IList tiene más sentido en un caso particular, usaré una convención de nomenclatura para que esos métodos se destaquen entre la multitud. –

+4

El problema con devolver 'IEnumerable ' es si decide convertirlo en 'IQuerable ' ya no está consultando al DB, sino a los objetos en la memoria. Como James Curran señaló que 'IQueryable' es un poco fuerte, pero en la mayoría de mis escenarios, me parece que ofrecer un set back indagable es mejor y dejar que el consumidor decida si quiere lanzarlo a IEnumerable. –

3

yo elegiría IEnumerable porque tiene un lugar más central en el marco, proporcionando versatilidad para aquellos que lo necesitan, mientras que también proporciona la familiaridad para aquellos que aún no se han metido en cosas como LINQ.

+0

Me gusta IEnumerable, si hubiera una forma de dar es un método de Cuenta. Sé que es inherente a ser perezoso no saber cuántos hay, ¡pero la propiedad Count es simplemente algo que necesitas tantas veces! –

+0

LINQ proporciona un método de extensión Count para IEnumerable. –

+0

@Jeff no es una buena idea si el original era un IQueryable (se recuperaría y contabilizaría). – eglasius

2

IQueryable tendría un requisito bastante pesado en él - no se podía, por ejemplo, devolver una matriz.

Por lo general, para mí, la elección entre IEnumerable o IList generalmente termina siendo la que sea más fácil de implementar en el caso estándar.

+0

Lo mismo para mí hasta ahora. Pero estoy tratando de ser un poco más consistente en mi estilo de programación. Y pensé que lanzaría IQueryable porque las interfaces de fluidos por lo general se ven muy legibles. –

2

Respuesta corta: Depende.

Respuesta más larga: devuelva el tipo más rico que su código de cliente va a necesitar. IList funciona en la mayoría de los casos si no necesita carga diferida. Todavía puede usar Linq para consultar contra un IList o IEnumerable. Si la carga lenta es un requisito, entonces vaya con IEnumerable o IQueryable.

Nota al margen: Volviendo la misma interfaz para todos los servicios puede parecer una meta noble pero teniendo en cuenta los diferentes patrones de uso del cliente, es posible que desee devolver diferentes interfaces.

+0

Es cierto, tal vez una convención de nomenclatura dependiendo de la pereza/no perezoso podría ser interesante. –

+0

Yo diría al revés. IList proporciona mucho más que IEnumerable, por lo que debe elegir IEnumerable, independientemente de la evaluación diferida, a menos que necesite métodos adicionales como Agregar, Eliminar e Indizar. –

2

Siempre ir con IEnumerable menos que tenga una razón de peso para no hacerlo. A continuación, puede implementar el captador con yield return.

IQueryable es un hervidor de agua totalmente diferente de los peces. No es algo que implemente casualmente como una alternativa a un contenedor típico en memoria.

Por lo demás, es una de las principales diferente entre IEnumerable y los otros: es de sólo lectura.

+0

Lanzar un valor de retorno a IEnumerable no lo hace de solo lectura: puede ser devuelto por el llamado. Si lo que quiere es de solo lectura, ajuste el resultado en una recopilación de solo lectura (por ejemplo, usando List (T) .AsReadOnly) antes de devolverlo. Normalmente devuelvo IList (T) o ICollection (T) ya que las personas que llaman a menudo quieren un conteo. – Joe

+1

Por supuesto, quiero decir que está tipado estáticamente para que sea de solo lectura. También podría decir: "No tiene sentido que los campos sean privados; pueden usar el reflejo para llegar a ellos de todos modos". –

3

Mi regla de oro es el siguiente:

Si alguna vez hay una posibilidad de que puedo tomar algoritmo central de la rutina y refactorearlo de manera que pueda utilizar retornos de rendimiento, que irá con IEnumerable <T>.

Por ejemplo, si mi aplicación actual utiliza una matriz o una lista <T> internamente, pero sé que, al menos teóricamente, es posible que quiera y ser capaz de volver a trabajar internamente para hacer la evaluación perezosa, me quedo devuelva un IEnumerable <T>.

He encontrado que las ganancias de devolver IEnumerable <T> definitivamente valen la molestia de usarlo.

Sin embargo, si el algoritmo, en su propia naturaleza, va a necesitar evaluar completamente los resultados antes de regresar (raro, pero sucede), voy a ir con un IList <T>. Básicamente, si ya lo estoy computando, lo devolveré. IList <T> implementa IEnumerable <T>, por lo que todos los casos de uso relacionados con LINQ siguen funcionando, pero pierde la evaluación perezosa. Si ya estoy obligado a evaluar por adelantado, eso no es un problema, sin embargo.

Casi nunca devuelvo IQueryable. La única vez que usaría esta interfaz es si estoy creando directamente una capa de acceso a datos consultable, o algo similar. La sobrecarga de usar esto es, en la mayoría de los casos, no vale la pena las ganancias.

Sin embargo, si su objetivo es usar siempre una sola interfaz (no necesariamente estoy de acuerdo con este objetivo), me quedaría con IEnumerable <T>.

0

Si usa IQueryable como tipo de devolución, tiene una capa de servicio con abstracción con fugas.

Cuestiones relacionadas