'How does the behavior of .Take() changes based on the interface reference I'm using on left. IQueryable vs IEnumerable
Assume I've these sample codes
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);
}
and
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);
}
the only difference between these to is the the reference I'm using IQueryable vs IEnumerable. 1st snippet is generating sql query to get top 1 item matching the filter criteria and the later is generating a sql query without top filter.
In both the cases, the object inside the data is of type Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable however the topEmp in the first scenaro is of type : Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable and in second it is System.Linq.Enumerable.EnumerablePartition
How the behavior of the .Take method changes based on the interface reference on the left. I see the "data" varialbe is of same type in both cases. As per my understanding, if the left side reference is a class then .Take of that class could get called; but they are interfaces. I'm sure I'm missing a basic concept of C# here.
Solution 1:[1]
You are correct that you've missed a basic concept of C#, and this concept is extension methods.
We are not calling an abstract Take
method implemented by the Enumerable
object.
Instead, we are invoking a function that exists separately to the object: the Take
extension methods. There are different methods based upon the type of object.
Inside the System.Core library exist these static classes.
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...
}
Extension methods are resolved at compile time, not runtime.
Your data
variable happens to implement IQueryable<T>
. But, once you've cast it to an IEnumerable<T>
, the compiler must choose the IEnumerable<T>
extension method.
Solution 2:[2]
You are not calling the same .Take()
methods.
Enumerable.Take
returns a new IEnumerable
that will enumerate items in the enumeration and yield them.
Queryable.Take
returns a new IQueryable
, to represent an Expression
tree. When you start enumerating that queryable, the expression will be compiled into SQL.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | marc_s |