¿Es AsList () mejor que ToList () con IDbConnection.Query () que devuelve IEnumerable?

c# dapper database-performance linq performance

Pregunta

Leí esta respuesta de Marc Gravell (@MarcGravell): https://stackoverflow.com/a/47790712/5779732

La última línea dice:

Como una optimización menor para su código: prefiera AsList () a ToList () para evitar crear una copia.

Esa declaración es sobre QueryMultiple() que devuelve GridReader .

Según entiendo, System.Linq proporciona un método de extensión IEnumerable.ToList() . Lo siguiente es de Microsoft sobre ToList() .

El método ToList (IEnumerable) fuerza la evaluación de consulta inmediata y devuelve una lista que contiene los resultados de la consulta. Puede agregar este método a su consulta para obtener una copia en caché de los resultados de la consulta.

IDbConnection.Query() SIEMPRE devolverá IEnumerable o null . La verificación nula podría hacerse fácilmente en el código de llamada. ¿Qué diferencia hace AsList entonces?

Si mi comprensión es correcta, AsList siempre llamará internamente a ToList que creará una copia.

Teniendo esto en cuenta, ¿es AsList() mejor que ToList() con IDbConnection.Query() que devuelve IEnumerable ? En caso afirmativo; ¿por qué?

¿Qué es lo que hace AsList() internamente que lo convierte en una mejor opción en este caso?

Respuesta aceptada

AsList es un método de extensión Dapper personalizado. Todo lo que hace es comprobar si IEnumerable<T> le pasas es realmente List<T> . Si lo es, lo devuelve, simplemente lo envía a List<T> . Si no es así, llama a ToList regular. El punto es: ToList() siempre crea una copia, incluso si lo que le pasa ya es una lista. AsList() método AsList() evita hacer esta copia, por lo que es útil si dicha copia no es necesaria.

En este escenario específico, tiene el siguiente código:

multipleresult.Read<MerchantProduct>()

donde multipleresult es GridReader . Read tiene un argumento de buffered que es verdadero por defecto. Cuando es verdadero - Read realmente devolverá List<T> , así que al llamar a ToList copiará esa lista nuevamente sin mucha razón.

Lo mismo es cierto para IDbConnection.Query() - también tiene un parámetro de buffered , que es verdadero de manera predeterminada, por lo que también devolverá por defecto List<T> .

Si prefiere usar ToList() , puede pasar buffered: false a Query() o Read() para evitar crear esa copia adicional.


Respuesta popular

Esta extensión es una extensión personalizada que hace una comprobación adicional antes de llamar a ToList . Fuente :

public static List<T> AsList<T>(this IEnumerable<T> source) 
    => (source == null || source is List<T>) ? (List<T>)source : source.ToList();
  • ToList siempre crea una nueva instancia de List<T> y la rellena con los elementos ToList
  • AsList comprueba si la secuencia ya es una List<T> , entonces simplemente la lanzará

Por supuesto, este enfoque puede ser más eficiente porque lanzar algo es mucho menos trabajo que crear y llenar algo nuevo. Entonces es completamente diferente.

Esto es una especie de opinión, pero me parece peligroso . Alguien puede pasar por alto AsList y leer ToList o simplemente no sabe la diferencia. Es peligroso si alguien cambia el código más tarde.

Entonces, por ejemplo, un método que toma IEnumerable<T> que usa AsList :

public static List<T> GetResult<T>(IEnumerable<T> seq)
{
    if(some condition here)
    {
        seq = seq.Where(some predicate here);
    }
    return seq.AsList()
}

Ahora el código llamó a este método con una lista:

IEnumerable<string> sequence = (gets a list from somewhere)
List<string> userList = GetResult(sequence);

Más tarde alguien decide que una matriz es más apropiada aquí:

IEnumerable<string> sequence = (gets an array from somewhere)
List<string> userList = GetResult(sequence);

Esto realmente no duele hasta ahora. Ahora se inicializa y completa una nueva lista porque la fuente no es una lista y no se puede convertir. Entonces es menos eficiente. Pero si la lógica también se basó en que la lista es la misma referencia, esto ya no funcionará.

if(userList == seq)
{
    // do something
}

Esto siempre es false una vez que se usa la matriz. Entonces el código se rompió en silencio.

Para abreviar: no me gusta el método AsList . Siempre puede verificar el tipo usted mismo.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué