Ngôn ngữ LINQ - Thực thi trì hoãn

Thực thi truy vấn LINQ

Có hai kịch bản thực thi truy vấn LINQ:

  • Trì hoãn thực thi truy vấn LINQ (Deferred Execution of LINQ Query).
  • Thực thi ngay lập tức truy vấn LINQ (Immediate Execution of LINQ Query).

Trì hoãn thực thi truy vấn LINQ

Trì hoãn thực thi là gì?

Trì hoãn thực thi có nghĩa là việc đánh giá một biểu thức bị trì hoãn cho đến khi giá trị thực sự của nó được yêu cầu.

Trì hoãn thực thi truy vấn LINQ giúp cải thiện đáng kể hiệu suất bằng cách tránh thực thi không cần thiết.

Việc trì hoãn thực thi được áp dụng trên mọi tập hợp trong bộ nhớ cũng như các trình cung cấp LINQ từ xa như LINQ-to-SQL, LINQ-to-Entities, LINQ-to-XML, v.v.

Hình ảnh đưới đây minh họa trì hoãn thực thi truy vấn LINQ:

Trì hoãn thực thi truy vấn LINQ

Trong ví dụ trên, bạn có thể thấy truy vấn được thực thi khi bạn thực hiện duyệt danh sách bằng vòng lặp foreach.

Điều này được gọi là trì hoãn thực thi.

LINQ xử lý danh sách studentList khi bạn thực sự truy cập từng đối tượng trong danh sách và làm một cái gì đó với nó.

Trì hoãn thực thi trả về dữ liệu mới nhất

Để kiểm tra xem việc trì hoãn thực thi có trả lại dữ liệu mới nhất mỗi lần hay không, hãy thêm một sinh viên tuổi teen sau vòng lặp foreach và kiểm tra danh sách teenAgerStudents như sau:

Trì hoãn thực thi truy vấn LINQ

Như bạn có thể thấy, vòng lặp foreach thứ hai thực hiện lại truy vấn và trả về dữ liệu mới nhất.

Việc trì hoãn thực thi sẽ thực hiện đánh giá lại trên mỗi lần thực thi; điều này được gọi là lazy evaluation. Đây là một trong những lợi thế chính của việc trì hoãn thực thi: nó luôn cung cấp cho bạn dữ liệu mới nhất.

Triển khai trì hoãn thực thi

Bạn có thể triển khai trì hoãn thực thi cho các phương thức mở rộng tùy chỉnh của mình cho interface IEnumerable bằng cách sử dụng từ khóa yield của C#.

Ví dụ: bạn có thể triển khai phương thức mở rộng tùy chỉnh GetTeenAgerStudents cho IEnumerable trả về danh sách tất cả học sinh là thanh thiếu niên.

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;
            }
        }
    }
}

Lưu ý rằng chúng tôi sẽ in tên sinh viên bất cứ khi nào phương thức GetTeenAgerStudents() được gọi.

Bây giờ bạn có thể sử dụng phương thức mở rộng này như dưới đây:

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);
}

Đây là kết quả khi biên dịch và thực thi chương trình:

Accessing student John
Student Name: John
Accessing student Steve
Student Name: Steve
Accessing student Bill
Student Name: Bill
Accessing student Ram
Accessing student Ron

Xem ví dụ

Như bạn có thể thấy từ đầu ra, phương thức GetTeenAgerStudents() sẽ được gọi khi bạn duyệt studentList bằng cách sử dụng vòng lặp foreach.

Trì hoãn thực thi truy vấn LINQ

Vì vậy, theo cách này bạn có thể tạo các phương thức mở rộng tùy chỉnh bằng cách sử dụng từ khóa yield để có được lợi thế của việc trì hoãn thực thi.