'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