Difference between IQueryable, IEnumerable, IList and List

Here I will explain to you when to use what and its use cases.

IQueryable

IQueryable<T> provides a powerful mechanism for querying data from different sources using LINQ and is especially useful when working with large databases.

Deferred execution

when you build a query using IQueryable<T>, the query is not executed immediately. Instead, it is executed when the query results are enumerated, typically using methods like ToList(), First(), or a foreach loop. This allows for optimization and efficient query execution.

Example

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// Assume we have a collection of Person objects
List<Person> people = new List<Person>
{
    new Person { Name = "John", Age = 30 },
    new Person { Name = "Alice", Age = 25 },
    new Person { Name = "Michael", Age = 40 },
    new Person { Name = "Emily", Age = 35 }
};
// Convert the collection to an IQueryable<Person>

IQueryable<Person> queryablePeople = people.AsQueryable();

var query = queryablePeople.Where(p => p.Age > 25).OrderBy(p => p.Name);
//here above query doesn't hold the final result

foreach (var person in query) // The query is executed and the results are accessed
{
    Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");
}

IEnumerable

In the context of LINQ and lazy evaluation, "deferred" or "lazy" evaluation refers to the behavior where the execution of an operation or query is delayed until its results are needed or accessed. This allows for more efficient use of resources by avoiding unnecessary computations.

In LINQ, most operations on IEnumerable<T> sequences, such as filtering, mapping, and order, are evaluated lazily. This means that when you define a LINQ query by chaining multiple operations together, the query is not executed immediately. Instead, it creates an expression tree that represents the query logic.

The evaluation happens at the point where you iterate over the elements of the sequence, typically by using a foreach loop, calling a terminal operation like ToList(), ToArray(), or Count(), or performing some other action that requires the elements of the sequence.

Example of lazy evaluation

IEnumerable<int> numbers = Enumerable.Range(1, 10);

var query = numbers.Where(x => x % 2 == 0).Select(x => x * x);
// The query has not been executed yet
foreach (var number in query) // The query is executed, and the results are accessed
{
    Console.WriteLine(number);
}

IList<T>

IList<T> provides more flexibility because it allows you to use different implementations that conform to the IList<T> contract. This flexibility can be useful if you need to switch between different implementations. If you want to abstract away the implementation details or require the flexibility to switch between different implementations, using IList<T> the type or parameter can be beneficial.

Use case: For example, if you want to implement custom classes by inheriting IList<T> in your application, you can go with IList<T>  and have your own implementation.

List<T>

List<T> provides additional methods beyond those defined in the IList<T> interface. For example, List<T> has specific plans like Capacity, TrimExcess, and Sort that are not available in IList<T>. If you need these additional methods, using List<T> would be necessary. 

Summary

IList<T> and List<T> don't support lazy/deferred execution in Linq, but it gives more flexibility and additional functionality for data manipulation.

IEnumberable<T> and IQuerable<T> support are lazy/deferred execution, so they are the most efficient in terms of performance optimization.


Similar Articles