Ercan Erdoğan
4 min readFeb 12, 2024

What are these IEnumarable and IQueryable interfaces and what are the differences between each other?

IEnumarable

IEnumerable is an interface that represents a sequence of objects that can be enumerated. It has a single method, GetEnumerator, that returns an IEnumerator object, which can be used to iterate through the sequence. IEnumerable works with in-memory collections and executes the query on the client side. It uses LINQ to Objects, which means that it can only use the methods and operators defined in the Enumerable class. IEnumerable loads the entire collection into memory before applying any filters or transformations, which can be inefficient for large collections or complex queries. IEnumerable is suitable for simple queries on small collections.

IQueryable

IQueryable is an interface that inherits from IEnumerable and provides functionality to evaluate queries against a specific data source, such as a database or a web service. It has two additional properties, Expression and Provider, that store the expression tree and the query provider of the data source. IQueryable works with out-of-memory collections and executes the query on the server side, using the query provider of the data source. It uses LINQ to SQL, LINQ to Entities, or any other LINQ provider, which means that it can use the methods and operators defined in the Queryable class, as well as translate the query expression into the native language of the data source, such as SQL. IQueryable applies the filters and transformations before loading the data into memory, which reduces the memory usage and improves the performance. IQueryable is suitable for complex queries on large collections or remote data sources.

IEnumerable and IQueryable are both interfaces that allow us to manipulate and query collections of data. However, they have some important differences that affect their performance and usage.

  • IEnumerable is defined in the System.Collections namespace and IQueryable is defined in the System.Linq namespace.
  • IQueyable inherits from IEnumerable, which means that IQueryable has all the features of IEnumerable and some additional ones such as Expression and Provider. This also means that we can use IQueryable as IEnumerable, but not vice versa. For example, we can use the foreach loop to iterate over an IQueryable collection, but we cannot use the Queryable methods on an IEnumerable collection.
  • IEnumerable works with in-memory collections, while IQueryable works with out-of-memory collections, such as databases or web services.
  • IEnumerable executes the query on the client side, while IQueryable executes the query on the server side, using the query provider of the data source.
  • IEnumerable uses LINQ to Objects, which means that it can only use the methods and operators defined in the Enumerable class. IQueryable uses LINQ to SQL, LINQ to Entities, or any other LINQ provider, which means that it can use the methods and operators defined in the Queryable class, as well as translate the query expression into the native language of the data source, such as SQL.
  • IEnumerable loads the entire collection into memory before applying any filters or transformations, while IQueryable applies the filters or transformations before loading the data into memory, which reduces the memory usage and improves the performance.
  • IEnumerable is suitable for simple queries on small collections, while IQueryable is suitable for complex queries on large collections or remote data sources.

Here is a code example that illustrates the difference between IEnumerable and IQueryable:

using System;
using System.Collections.Generic;
using System.Linq;

namespace LINQDemo
{
class Program
{
static void Main(string[] args)
{
// Create a list of students
List<Student> students = new List<Student>()
{
new Student { ID = 101, FirstName = "Steve", LastName = "Smith", Gender = "Male" },
new Student { ID = 102, FirstName = "Sara", LastName = "Pound", Gender = "Female" },
new Student { ID = 103, FirstName = "Ben", LastName = "Stokes", Gender = "Male" },
new Student { ID = 104, FirstName = "Jos", LastName = "Butler", Gender = "Male" },
new Student { ID = 105, FirstName = "Pam", LastName = "Semi", Gender = "Female" }
};

// Use IEnumerable to get the top 2 male students
IEnumerable<Student> maleStudents = students.Where(s => s.Gender == "Male").Take(2);

// Use IQueryable to get the top 2 male students
IQueryable<Student> maleStudentsQuery = students.AsQueryable().Where(s => s.Gender == "Male").Take(2);

// Display the results
Console.WriteLine("Using IEnumerable:");
foreach (var student in maleStudents)
{
Console.WriteLine(student.FirstName + " " + student.LastName);
}

Console.WriteLine("Using IQueryable:");
foreach (var student in maleStudentsQuery)
{
Console.WriteLine(student.FirstName + " " + student.LastName);
}
}
}

// Define a student class
class Student
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
}
}

The output of the program is:

Using IEnumerable:
Steve Smith
Ben Stokes
Using IQueryable:
Steve Smith
Ben Stokes

However, the difference is not visible in the output, but in the way the query is executed. We can see below the SQL statements that are generated by the IQueryable query, which are:

-- Region Parameters
DECLARE @p0 NVarChar(1000) = 'Male'
DECLARE @p1 Int = 2
-- EndRegion
SELECT TOP (@p1) [t0].[ID], [t0].[FirstName], [t0].[LastName], [t0].[Gender]
FROM [Student] AS [t0]
WHERE [t0].[Gender] = @p0

As we can see, the IQueryable query applies the filter and the limit on the server side, before returning the data to the client. This reduces the amount of data that is transferred and processed, which improves the performance and efficiency of the query.

Conclusion:

Use IEnumerable when working with in-memory collections or when the data is already in memory.

Use IQueryable when dealing with external data sources, like databases, where you want to perform efficient querying without loading all the data into memory.

In many cases, LINQ methods can be used interchangeably with both interfaces, but understanding the underlying behavior and choosing the appropriate interface can lead to more efficient and optimized queries, especially when dealing with large datasets and external data sources.

Resources: