Supongamos que tengo estos códigos de muestra
IQueryable<Employee> data = context.Employees.Where(x => x.FullName != "Shekar Reddy"); var topEmp = data.Take(1); foreach (var item in topEmp) { Console.WriteLine(item.FullName); }y
IEnumerable<Employee> data = context.Employees.Where(x => x.FullName != "Shekar Reddy"); var topEmp = data.Take(1); foreach (var item in topEmp) { Console.WriteLine(item.FullName); }la única diferencia entre estos es la referencia que estoy usando IQueryable vs IEnumerable. El primer fragmento genera una consulta sql para obtener el primer elemento que coincida con los criterios de filtro y el último genera una consulta sql sin el filtro principal.
En ambos casos, el objeto dentro de los datos es de tipo Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable, sin embargo, topEmp en el primer escenario es de tipo: Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable y en segundo es System.Linq .Enumerable.EnumerablePartition
Cómo cambia el comportamiento del método .Take según la referencia de la interfaz de la izquierda. Veo que el varialbe de "datos" es del mismo tipo en ambos casos. Según tengo entendido, si la referencia del lado izquierdo es una clase, entonces se podría llamar a .Take de esa clase; pero son interfaces. Estoy seguro de que me falta un concepto básico de C# aquí.
No está llamando a los mismos métodos .Take() .
Enumerable.Take devuelve un nuevo IEnumerable que enumerará los elementos de la enumeración y los producirá.
Queryable.Take devuelve un nuevo IQueryable para representar un árbol de Expression . Cuando comience a enumerar ese consultable, la expresión se compilará en SQL.
Tiene razón en que se ha perdido un concepto básico de C#, y este concepto son los métodos de extensión .
No estamos llamando a un método Take abstracto implementado por el objeto Enumerable .
En cambio, estamos invocando una función que existe por separado del objeto: los métodos de extensión Take . Existen diferentes métodos basados en el tipo de objeto.
Dentro de la biblioteca System.Core existen estas clases estáticas.
public static class Queryable { public static IQueryable<TSource> Take<TSource>( this IQueryable<TSource> source, int count ); // Many other methods... } public static class Enumerable { public static IEnumerable<TSource> Take<TSource>( this IEnumerable<TSource> source, int count ); // Many other methods... }Los métodos de extensión se resuelven en tiempo de compilación, no en tiempo de ejecución.
Su variable de data implementa IQueryable<T> . Pero, una vez que lo haya convertido en IEnumerable<T> , el compilador debe elegir el método de extensión IEnumerable<T> .