2011-04-12 11 views
5

¿Cuál es el enfoque común para las aplicaciones de diseño, que confían fuertemente en la evaluación perezosa en C# (LINQ, IEnumerable, IQueryable, ...)?C# pregunta de la pereza

En este momento lo general intento de hacer todas las consultas tan vago como sea posible, utilizando yield return y LINQ consultas, pero en tiempo de ejecución de este por lo general podría conducir a "pereza" comportamiento, cuando cada consulta obtiene a obra desde su comienzo, obviamente, resulta en la degradación severa del rendimiento visual.

lo que suelo hacer significa poner ToList() operadores de proyección algún lugar para almacenar en caché los datos, pero sospecho que este enfoque podría ser incorrecta.

¿Cuál es la manera apropiada/comunes para el diseño de este tipo de aplicaciones, desde el principio?

Respuesta

4

Me parece útil para clasificar cada IEnumerable en una de tres categorías.

  1. fast ones - e.g. listas y matrices
  2. lentas, p. ej.consultas de bases de datos o cálculos pesados ​​
  3. no deterministas, p. ej. list.Select (x => nueva {...})

Para la categoría 1, tiendo mantener el tipo inmediato cuando sea apropiado, matrices o IList etc. Para la categoría 3, los son los mejores para mantener local dentro de un método para evitar errores difíciles de encontrar. Luego tenemos la categoría 2 y, como siempre, al optimizar el rendimiento, mida primero para encontrar los cuellos de botella.

2

Unos pocos pensamientos al azar - como la cuestión en sí está vagamente definidos:

  • perezoso es buena sólo cuando el resultado no podría ser utilizado, por tanto, cargado sólo cuando sea necesario. La mayoría de las operaciones, sin embargo, necesitarían que los datos se carguen para que la pereza no sea buena en ese término.
  • La pereza puede causar errores difíciles. Hemos visto todo con contextos de datos en ORM
  • perezoso es bueno cuando se trata de MEF
1

Te necesito una cierta secuencia de datos para almacenar en caché, llamar a uno de los operadores de agregación (ToList, ToArray, etc.) en esa secuencia. De lo contrario, solo use la evaluación perezosa.

Construya su código alrededor de sus datos. ¿Qué datos son volátiles y deben extraerse cada vez? Use evaluación diferida y no caché. ¿Qué datos son relativamente estáticos y solo se deben extraer una vez? Guarde en caché esos datos en la memoria para que no los tire innecesariamente.

2

Bastante amplia cuestión y, lamentablemente, vamos a escuchar mucho en esto: Depende. Lazy-loading es genial hasta que no lo es.

En general, si estás usando los mismos IEnumerables una y otra podría ser mejor para almacenar en caché como listas.

Pero raras veces tiene sentido para las personas que llaman para saber esto de cualquier manera. Es decir, si obtiene IEnumerables de un repositorio o algo así, es mejor dejar que el repositorio haga su trabajo. Puede almacenarlo en caché como una lista internamente o puede crearlo cada vez. Si las personas que llaman tratar de conseguir demasiado inteligente que podrían perderse los cambios en los datos, etc.

2

Yo sugeriría hacer una ToList en su DAL antes de devolver el DTO

public IList<UserDTO> GetUsers() 
{ 
    using (var db = new DbContext()) 
    { 
    return (from u in db.tblUsers 
      select new UserDTO() 
      { 
       Name = u.Name 
      }).ToList(); 
    } 
} 

En el ejemplo anterior, puede tener hacer una ToList() antes de que finalice el alcance de DbContext.

+1

Holy moly! ¡Tengo una tonelada métrica de código que se ve casi idéntica a esto! :) –

0

La ejecución diferida y el almacenamiento en caché de todos los artículos con .ToList() no son las únicas opciones. La tercera opción es almacenar en caché los elementos mientras que está iterando mediante el uso de una lista diferida.

La ejecución aún se ha aplazado, pero todos los elementos solo se otorgan una vez. Un ejemplo de cómo este trabajo:

public class LazyListTest 
{ 
    private int _count = 0; 

    public void Test() 
    { 
     var numbers = Enumerable.Range(1, 40); 
     var numbersQuery = numbers.Select(GetElement).ToLazyList(); // Cache lazy 
     var total = numbersQuery.Take(3) 
      .Concat(numbersQuery.Take(10)) 
      .Concat(numbersQuery.Take(3)) 
      .Sum(); 
     Console.WriteLine(_count); 
    } 

    private int GetElement(int value) 
    { 
     _count++; 
     // Some slow stuff here... 
     return value * 100; 
    } 
} 

Si ejecuta el método de prueba(), el _count sólo 10. Sin el almacenamiento en caché sería 16 y con. ToList() ¡sería 40!

Un ejemplo de implementation of LazyList can be found here.