IEnumerable
LINQ
C# programming
.NET framework
data querying

Does LINQ work with IEnumerable?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Yes, LINQ absolutely works with IEnumerable<T>, and in fact this is the most common way LINQ is used. LINQ to Objects is the flavor of LINQ that operates on in-memory collections implementing IEnumerable<T>, giving you a declarative, SQL-like syntax for filtering, projecting, and transforming data. Understanding how LINQ interacts with IEnumerable<T> versus IQueryable<T> is key to writing efficient C# code and avoiding performance surprises.

How LINQ Works with IEnumerable

LINQ to Objects is implemented as a set of extension methods defined in the System.Linq namespace. Any type that implements IEnumerable<T> (lists, arrays, dictionaries, hash sets, and custom collections) can use these methods:

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
6
7// Query syntax
8var evenQuery = from n in numbers
9                where n % 2 == 0
10                select n;
11
12// Method syntax (more common)
13var evenMethod = numbers.Where(n => n % 2 == 0);
14
15foreach (var num in evenMethod)
16{
17    Console.WriteLine(num);  // 2, 4, 6, 8, 10
18}

Both syntax forms compile to the same extension method calls. The method syntax using lambda expressions is more widely used in practice because it is more flexible and composable.

Deferred vs Immediate Execution

One of the most important concepts to understand about LINQ with IEnumerable<T> is deferred execution. Most LINQ methods do not execute when you call them. Instead, they build up a query that runs only when you iterate over the result:

csharp
1List<string> names = new List<string> { "Alice", "Bob", "Charlie" };
2
3// This does NOT execute the query yet
4var query = names.Where(n => n.Length > 3);
5
6// The list is modified after the query is defined
7names.Add("Diana");
8
9// NOW the query executes, and Diana is included
10foreach (var name in query)
11{
12    Console.WriteLine(name);  // Alice, Charlie, Diana
13}

Deferred execution means the query reflects the current state of the data source at the time of iteration, not at the time of definition. Methods like ToList(), ToArray(), Count(), First(), and Sum() trigger immediate execution because they must consume the entire sequence (or find a specific element) to produce their result.

csharp
1// Immediate execution: creates a snapshot
2List<string> snapshot = names.Where(n => n.Length > 3).ToList();
3
4names.Add("Evelyn");
5
6// snapshot does NOT contain Evelyn
7Console.WriteLine(snapshot.Count);  // 3

Common LINQ Methods

Here are the most frequently used LINQ methods on IEnumerable<T>:

csharp
1var products = new List<Product>
2{
3    new Product { Name = "Laptop", Category = "Electronics", Price = 999.99m },
4    new Product { Name = "Shirt", Category = "Clothing", Price = 29.99m },
5    new Product { Name = "Phone", Category = "Electronics", Price = 699.99m },
6    new Product { Name = "Jacket", Category = "Clothing", Price = 89.99m },
7    new Product { Name = "Tablet", Category = "Electronics", Price = 449.99m },
8};
9
10// Where: filter elements
11var expensive = products.Where(p => p.Price > 100);
12
13// Select: project/transform elements
14var productNames = products.Select(p => p.Name);
15
16// OrderBy / OrderByDescending: sort elements
17var sorted = products.OrderBy(p => p.Price);
18
19// GroupBy: group elements by a key
20var grouped = products.GroupBy(p => p.Category);
21
22foreach (var group in grouped)
23{
24    Console.WriteLine($"{group.Key}: {group.Count()} items");
25}
26// Electronics: 3 items
27// Clothing: 2 items
28
29// Chaining multiple operations
30var result = products
31    .Where(p => p.Category == "Electronics")
32    .OrderByDescending(p => p.Price)
33    .Select(p => new { p.Name, p.Price });

Each of these methods returns a new IEnumerable<T> (or IOrderedEnumerable<T> for sorting), allowing you to chain operations together fluently. The entire chain uses deferred execution until you iterate or materialize the results.

IEnumerable vs IQueryable

Understanding the difference between IEnumerable<T> and IQueryable<T> is critical for performance. Both support LINQ, but they execute queries in fundamentally different ways:

csharp
1// IEnumerable<T>: executes in memory using delegates
2IEnumerable<Product> memoryQuery = products
3    .Where(p => p.Price > 100)
4    .OrderBy(p => p.Name);
5
6// IQueryable<T>: builds expression trees, translates to SQL
7IQueryable<Product> dbQuery = dbContext.Products
8    .Where(p => p.Price > 100)
9    .OrderBy(p => p.Name);
10// Generates: SELECT * FROM Products WHERE Price > 100 ORDER BY Name

With IEnumerable<T>, the lambda expressions are compiled into delegates and executed in your application's memory. With IQueryable<T>, the same lambda expressions are converted into expression trees that a provider (like Entity Framework) translates into SQL. If you accidentally cast an IQueryable<T> to IEnumerable<T> early in a chain, all subsequent filtering happens in memory instead of in the database:

csharp
1// BAD: pulls ALL products into memory, then filters
2IEnumerable<Product> allProducts = dbContext.Products;
3var filtered = allProducts.Where(p => p.Price > 100);
4
5// GOOD: filtering happens in the database
6var filtered = dbContext.Products.Where(p => p.Price > 100);

Materializing Results with ToList and ToArray

When you need to force execution and capture the results at a specific point in time, use ToList() or ToArray():

csharp
1var numbers = Enumerable.Range(1, 1000);
2
3// Deferred: re-evaluated every time you iterate
4var query = numbers.Where(n => n % 7 == 0);
5
6// Materialized: computed once, stored in memory
7List<int> list = query.ToList();
8int[] array = query.ToArray();
9
10// ToDictionary for key-value lookups
11Dictionary<string, decimal> priceMap = products
12    .ToDictionary(p => p.Name, p => p.Price);

Materialize results when you need to iterate multiple times over the same data, when you need a count without re-executing, or when you want to disconnect from a database context before it is disposed. Avoid materializing unnecessarily large sequences, as it allocates memory proportional to the collection size.

Common Pitfalls

  • Iterating a deferred query multiple times re-executes the entire pipeline each time, which can cause performance issues or inconsistent results if the source data changes between iterations.
  • Casting a database query to IEnumerable<T> too early causes all subsequent filtering to happen in memory instead of in SQL, potentially loading millions of rows unnecessarily.
  • Forgetting to add using System.Linq; at the top of the file means LINQ extension methods will not appear on IEnumerable<T>, leading to confusing compiler errors.
  • Adding or removing elements from the source collection while iterating a LINQ query throws an InvalidOperationException at runtime.
  • Relying on group ordering from GroupBy without an explicit OrderBy can lead to fragile code, since element order within groups is preserved but group ordering is not guaranteed across providers.

Summary

  • LINQ works seamlessly with IEnumerable<T> through extension methods in System.Linq, enabling declarative data querying on any in-memory collection.
  • Most LINQ operations use deferred execution, meaning the query runs only when you iterate the results, not when you define the query.
  • IEnumerable<T> executes with in-memory delegates while IQueryable<T> translates to database queries via expression trees. Mixing them up can cause severe performance problems.
  • Use ToList() or ToArray() to materialize results when you need a snapshot or plan to iterate multiple times.
  • Chain operations fluently to build readable pipelines. Elements flow through the chain one at a time, keeping memory usage efficient.

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.