2011-04-26 10 views
5

Tengo algunos métodos que devuelven una lista de T como dicen GetAllEvents. En algunos casos, necesito filtrar esa lista de eventos (o lo que sea que mi Lista sea) por fecha u otra propiedad en los ítems.LINQ si regreso Lista <T> O IEnumerable <T> cuando todavía puede hacer más tarde

Sé que las consultas LINQ pueden estar "encadenadas" o tener x número de líneas que las refinan aún más y la consulta no se ejecutará hasta cierto punto cuando realmente las necesite en una declaración no lineal (corregirme) si me equivoco en esta creencia)

Mi pregunta es, si mi método GetAllXXX devuelve una Lista de lo que sea que obtengo, es el método .ToList() que estoy usando al final de mi código GetAllXXX ejecutando el LINQ ? ¿Debería devolver IEnumerable en su lugar? Si solo para aquellos casos en los que necesito hacer algo más con los "resultados" ANTES de que realmente se ejecute la consulta.

Aquí hay un ejemplo de mi preocupación: tengo que decir 1000 eventos. GetAllEvents recuperará los 1000 y me dará una lista de ellos. Luego, dependiendo de en qué página esté el usuario, solo puede mostrar eventos de Hoy, esta semana o de una determinada categoría. Idealmente, cuando llegue el momento en que le muestro al usuario los 5 eventos que suceden hoy, realmente no quiero pasar los 1000 a través del cable y luego truncarlos a los 5 que realmente quieren. Sí, sé que todo es del lado del servidor en este punto, pero si todavía está asignando memoria para el 1000, estoy tratando de evitar esto.

¿Alguna sugerencia o sugerencia?

+1

* No devuelva 'List ' *. Pero puede considerar devolver 'IList '. –

Respuesta

12

Devuelve IEnumerable.

La conversión a List es rápida y sencilla, además de mantener la interfaz desacoplada tanto de la implementación de sus métodos como del uso de la salida.

En cuanto a su preocupación específica: si va a ser costoso devolver los 1000 eventos y procesarlos en el cliente, entonces debería considerar realizar algunos filtros en el servidor. Aún puede tener un método que devuelve todos los eventos, pero tiene versiones especializadas/optimizadas que devuelven las consultas más frecuentes. Los eventos de hoy serían un buen ejemplo.

+4

Estoy totalmente de acuerdo. Sin embargo, una advertencia pequeña que vale la pena considerar: si finalmente no convierte el IEnumerable a una matriz o lista, y realiza varias operaciones en ese IEnumerable, podría encontrarse realizando la consulta varias veces involuntariamente, lo que podría crear un serio problema de rendimiento. A veces no es una mala idea hacer que el tipo de retorno sea IEnumerable, pero aún así convertirlo a una matriz antes de devolver el objeto. – Phil

9

Si convierte la secuencia en una lista en el servidor, está usando el tiempo y la memoria en el servidor y luego la transmite por cable y luego usa más tiempo y memoria en el cliente para filtrar la lista .

Si solo devuelve la secuencia, entonces está "resolviendo" su problema creando un problema diferente. Ahora, cuando el cliente va a filtrar la lista, tiene que hacer mil visitas pequeñas al servidor en lugar de un costoso hit. La misma cantidad de información se transfiere por cable y lleva mucho más tiempo con todos los gastos generales por golpe.

Si lo que desea hacer es realizar el filtrado en el servidor, puede (1) crear una API personalizada que represente filtros comunes (fácil) o (2) devolver IQueryable e implementar un proveedor LINQ. (Difícil, pero poderoso.) IQueryable le permite construir la consulta en el lado del cliente, enviar la consulta por cable al servidor, ejecutar la consulta en el servidor, y luego solo servir los resultados que el cliente quería.

Mi colega Matt Warren escribió toda una serie de artículos sobre cómo implementar IQueryable; Yo comenzaría con eso.

8

La respuesta de Eric Lippert es buena, pero tenga en cuenta que no necesita implementar todo IQueryable si solo desea proporcionar algún filtro del lado del servidor (incluso el filtrado personalizado).Puede crear una API compatible con LINQ más simpy implementando solo las funciones LINQ que realmente usará. Por ejemplo, considere la definición

interface IOneTripEnumerable<T> : IEnumerable<T> 

que expone compatibles LINQ sólo Donde método con el tipo de retorno IOneTripEnumerable

La implementación de IOneTripEnumerable.Where volvería un nuevo objeto que también implementa IOneTripEnumerable y simplemente almacena el filtro como un miembro de datos. Cuando se llama a IOneTripEnumerable.GetEnumerator, puede empaquetar los filtros y enviarlos al servidor y luego recuperar los resultados filtrados en un viaje de ida y vuelta.

(También podría implementar una política de caché del cliente:. Si desea que las llamadas posteriores a GetEnumerator para devolver un empadronador durante los mismos resultados que la llamada inicial, simplemente almacenar los resultados en el objeto enumerable)

Si obtiene más tiempo y ve la necesidad, puede optimizar aún más agregando métodos LINQ adicionales, pero solo tomando el control de Dónde (para permitir que el filtrado ocurra en el servidor) y GetEnumerator (para obtener todos los resultados en una sola ronda). viaje) podría dar muy buenos resultados a bajo costo para implementar. No necesita implementar todo IQueryable. (Tenga en cuenta que Count, Any y Take son también muy buenos candidatos para la optimización de ida y vuelta y son triviales de implementar).

+0

Este es un buen punto; de hecho, la mayoría de los proveedores LINQ no implementan la gloria total de todas las características IQueryable posibles. –

Cuestiones relacionadas