Deferred Execution of LINQ Query

Deferred execution means that the evaluation of an expression is delayed until its realized value is actually required. It greatly improves performance by avoiding unnecessary execution.

Deferred execution is applicable on any in-memory collection as well as remote LINQ providers like LINQ-to-SQL, LINQ-to-Entities, LINQ-to-XML, etc.

Let's understand deferred execution using the following example:

Deferred Execution

In the above example, you can see the query is materialized and executed when you iterate using the foreach loop. This is called deferred execution. LINQ processes the studentList collection when you actually access each object from the collection and do something with it.

Deferred Execution returns the Latest Data

To check whether deferred execution returns the latest data each time, add one more teen ager student after the foreach loop and check the teenager student list:

Deferred Execution

As you can see, the second foreach loop executes the query again and returns the latest data. Deferred execution re-evaluates on each execution; this is called lazy evaluation. This is one of the major advantages of deferred execution: it always gives you the latest data.

Implementing Deferred Execution

You can implement deferred execution for your custom extension methods for IEnumerable using the yield keyword of C#.

For example, you can implement custom extension method GetTeenAgerStudents for IEnumerable that returns a list of all students who are teenagers.

Example: Implimenting Deferred Execution in C#
public static class EnumerableExtensionMethods
{
    public static IEnumerable<Student> GetTeenAgerStudents(this IEnumerable<Student> source)
    {

        foreach (Student std in source)
        {
            Console.WriteLine("Accessing student {0}", std.StudentName);

            if (std.age > 12 && std.age < 20)
                yield return std;
        }
    }
}

Notice that we print the student name on the console whenever GetTeenAgerStudents() gets called.

You can now use this extension method as below:

C#:
IList<Student> studentList = new List<Student>() { 
            new Student() { StudentID = 1, StudentName = "John", age = 13 } ,
            new Student() { StudentID = 2, StudentName = "Steve",  age = 15 } ,
            new Student() { StudentID = 3, StudentName = "Bill",  age = 18 } ,
            new Student() { StudentID = 4, StudentName = "Ram" , age = 12 } ,
            new Student() { StudentID = 5, StudentName = "Ron" , age = 21 } 
        };
            
var teenAgerStudents = from s in studentList.GetTeenAgerStudents() 
                        select s;

foreach (Student teenStudent in teenAgerStudents)
    Console.WriteLine("Student Name: {0}", teenStudent.StudentName);
Output:
Accessing student John
Student Name: John
Accessing student Steve
Student Name: Steve
Accessing student Bill
Student Name: Bill
Accessing student Ram
Accessing student Ron

As you can see from the output, GetTeenAgerStudents() is getting called when you iterate studentList using the foreach loop.

Deferred Execution
Deferred Execution

So, in this way you can create custom methods using the yield keyword to get the advantage of deferred execution.

Want to check how much you know LINQ?