IEnumerable vs IQueryable. Which one should I use?

Cornelius Tantius
Bina Nusantara IT Division
4 min readJun 29, 2023
Photo by Kelly Sikkema on Unsplash

In the realm of C# programming, the ability to manipulate and iterate through collections is a fundamental skill. Whether you’re working with small datasets or handling vast amounts of information, understanding the different collection types available to you is crucial. Among the most commonly used collection interfaces in C# are IEnumerable, IQueryable, and the concrete implementation List.

In this article, we are going to break down the difference between each interface, IEnumerable and IQueryable.

IEnumerable

Firstly, we dive into the world of IEnumerable, a fundamental interface that forms the backbone of many collection-related operations in C#. We explore how IEnumerable simplifies the process of iterating over elements, providing a standardized way to access, traverse, and manipulate data. With its simplicity and flexibility, IEnumerable enables seamless integration with various collection types, empowering developers to write concise and elegant code.

Operations performed on IEnumerable are typically executed in memory. When you apply filtering or projection operations, they are performed on the entire collection sequentially. This can be less efficient for large datasets or complex queries as it involves loading the entire collection into memory. Therefore, IEnumerable is used during:

  • Working with small in-memory collections, such as arrays or lists, and you need to perform basic iteration and simple operations like filtering or projection.
  • When you want to create custom collection classes and provide an iterator to access the elements sequentially.
  • When you are building utility methods or extension methods that operate on collections and need to support a wide range of collection types.

For example, when you do this query at IEnumerable:

MyDataContext dataList = new MyDataContext();
IEnumerable<Employee> list = dataList.Employees.Where(p => p.Name.StartsWith("S"));
list = list.Take<Employee>(10);

Therefore, what happened in the database side, the query executed will be:

SELECT [t0].[EmpID], [t0].[EmpName], [t0].[Salary] FROM [Employee] AS [t0]
WHERE [t0].[EmpName] LIKE @p0

And the Take<Employee>(10) method will be executed in memory. Keep in mind that IEnumerable provides read-only access to the collection, meaning you can iterate over the elements but cannot modify them directly.

IQueryable

Next, we venture into IQueryable, a more specialized interface designed for querying data sources in a flexible and efficient manner. IQueryable extends the functionality of IEnumerable by incorporating the concept of deferred execution and expression trees. By leveraging IQueryable, you gain the ability to construct complex queries, allowing for intelligent optimization and query translation to various data providers. We unravel the inner workings of IQueryable and showcase its advantages in scenarios where data retrieval and transformation are critical.

IQueryable supports deferred execution and intelligent query optimization. Query expressions defined on IQueryable are converted into expression trees, which can be analyzed and translated by query providers (e.g., Entity Framework) into optimized queries specific to the underlying data source. This allows for efficient querying and reduces the amount of data transferred between the data source and the application. Due to that, IQueryable usually used during:

  • When querying data from a data source that supports query execution, such as a database or a remote service.
  • When you need to perform complex querying operations, including filtering, sorting, joining, and aggregation, using LINQ syntax.
  • When you want to take advantage of deferred execution and query optimization capabilities provided by query providers like Entity Framework.

The execution example on IQueryable:

MyDataContext dataList = new MyDataContext();
IEnumerable<Employee> list = dataList.Employees.Where(p => p.Name.StartsWith("S"));
list = list.Take<Employee>(10);

Therefore, what happened on the database side, the query executed will be:

SELECT TOP 10 [t0].[EmpID], [t0].[EmpName], [t0].[Salary] FROM [Employee] AS [t0]
WHERE [t0].[EmpName] LIKE @p0

Notice any difference? yes, usign IQueryable, the Take<Employee>(10) method is actually converted into query and executed serverside. Like IEnumerable, IQueryable is read-only for querying purposes. However, it allows for the creation of new query expressions and the composition of multiple queries to define complex operations.

List

Finally, we examine the concrete implementation of List, a class that represents a strongly typed, ordered collection of objects. The list offers a versatile set of methods and properties, allowing for efficient insertion, deletion, and retrieval of elements. We explore the unique characteristics of List, such as its dynamic resizing capability and support for indexing operations, making it an excellent choice when dealing with collections that require frequent modifications.

Unlike IEnumerable and IQueryable, List is not specifically designed for querying or deferred execution. It provides direct access to elements through indexing operations and offers methods for the modification and retrieval of elements within the list. List operations are executed immediately and directly on the collection itself. List commonly used at:

  • When you need a modifiable and ordered collection of elements that allows for efficient insertion, deletion, and retrieval of items.
  • When you require indexing operations to access elements directly by their position.
  • When you want to work with a collection that maintains the order of elements and supports various modification operations like adding, removing, and replacing elements.

Yes, compared to IEnumerable and IQueryable, List offers full modifiability, allowing you to add, remove, and modify elements within the collection. It provides methods like Add, Remove, Insert, and Clear for modifying the contents of the list.

In conclusion, here are the recommended use case for each implementation:

  • IEnumerable, the most basic interface for iterating over a collection and provides the ability to enumerate the elements using a foreach loop but, it is suitable when you only need to iterate over the collection and perform read-only operations.
  • Use IQueryable when you want to represent a queryable data source, typically for querying databases using LINQ (Language Integrated Query). This interface is suitable when you need to query a data source using LINQ and want to defer the execution of the query until necessary.
  • Use List when you need a dynamically resizable collection that supports adding, removing, and modifying elements. It provides various methods to manipulate the collection, such as Add, Remove, Sort, etc.

--

--