Bài đăng nổi bật


Thực hiện hoãn lại và ngay lập tức trong LINQ

Các truy vấn LINQ có thể thực hiện theo hai cách khác nhau: hoãn lại và ngay lập tức. Bài đăng này trình bày cách hoạt động của cả hai mô hình thực thi này.

Với việc thực thi hoãn lại, chuỗi kết quả của một truy vấn LINQ không được tạo cho đến khi nó được yêu cầu. Lấy đoạn mã nhỏ này làm ví dụ:

  1. int[] numbers = { 1, 2, 3, 4, 5 };
  2. var result = numbers.Where(n => n >= 2 && n <= 4);
  3. Console.WriteLine(result.Max()); // <- query executes at this point
  4. // Output:
  5. // 4

Truy vấn này không thực sự thực thi cho đến khi Max () được gọi và kết quả cuối cùng là bắt buộc. Bạn sẽ có thể thấy điều này cho chính mình, nếu bạn bước qua mã trong trình gỡ lỗi. Khi trình gỡ lỗi đạt đến Max (), hãy lưu ý rằng con trỏ thực thi nhảy trở lại toán tử Where () của truy vấn để tạo ra kết quả cuối cùng.

Thực thi hoãn lại làm cho LINQ hiệu quả hơn, vì nó ngăn chặn việc thực thi đầy đủ các hoạt động theo chuỗi cho mỗi mục mà nó phải xử lý. Ví dụ mã dưới đây trình bày khái niệm về hoạt động chuỗi trong LINQ:

  1. string[] words = { "one", "two", "three" };
  2. var result = words.Select((w, i) => new { Index = i, Value = w }).Where(w => w.Value.Length == 3).ToList();
  3.  
  4. Debug.WriteLine("Prints index for words that have a string length of 3:");
  5. foreach(var word in result)
  6. Debug.WriteLine (word.Index.ToString());
  7.  
  8. // Output:
  9. // Prints index for words that have a string length of 3:
  10. // 0
  11. // 1

Thay vì LINQ đầu tiên phải lặp lại trên cả ba chuỗi (đầu tiên là Select(), sau đó đến Where () và cuối cùng là ToList ()), kết quả không được tạo cho đến khi nó gặp ToList (). Tuy nhiên, như chúng ta sẽ thấy trong giây lát, nó không chỉ có các hoạt động được xâu chuỗi, điều này làm cho việc thực thi hoãn lại trở nên mạnh mẽ.

Thêm các mục vào một truy vấn hiện có là một lợi ích khác của việc thực thi hoãn lại. Ví dụ này cho thấy khái niệm:

  1. List vegetables = new List { "Carrot", "Selleri" };
  2. var result = from v in vegetables select v;
  3. Debug.WriteLine("Elements in vegetables array (before add): " + result.Count());
  4. vegetables.Add("Broccoli");
  5. Debug.WriteLine("Elements in vegetables array (after add): " + result.Count());
  6. // Output:
  7. // Elements in vegetables array (before add): 2
  8. // Elements in vegetables array (after add): 3

"Broccoli" được thêm vào truy vấn hiện có, nhưng truy vấn không được thực thi cho đến khi đạt đến Count().

Thực thi hoãn lại làm cho việc kết hợp hoặc mở rộng các truy vấn trở nên hữu ích. Hãy xem ví dụ này, tạo một truy vấn cơ sở và sau đó mở rộng nó thành hai truy vấn riêng biệt mới:

  1. int[] numbers = { 1, 5, 10, 18, 23};
  2.  
  3. var baseQuery = from n in numbers select n;

  4. var oddQuery = from b in baseQuery where b % 2 == 1 select b;
  5.  
  6. Debug.WriteLine("Sum of odd numbers: " + oddQuery.Sum()); // <- query executes at this point
  7. var evenQuery = from b in baseQuery where b % 2 == 0 select b;
  8. Debug.WriteLine("Sum of even numbers: " + evenQuery.Sum()); // <- query executes at this point
  9.  
  10. // Output:
  11. // Sum of odd numbers: 29
  12. // Sum of even numbers: 28

Lưu ý cách thực thi truy vấn không được thực hiện cho đến khi đạt đến Sum().

Khi các truy vấn LINQ thực thi và đánh giá kịp thời, bạn có cái được gọi là thực thi ngay lập tức (như bạn có thể đoán bây giờ là sự tương phản chính xác với thực thi hoãn lại). Trên thực tế, tất cả các truy vấn LINQ, trả về giá trị singleton, sẽ thực thi ngay lập tức; chúng bao gồm ToList (), Average () và Sum (). Ngược lại, bạn có các toán tử như Where, Select và Take để thực hiện hoãn lại. Do đó, nếu bạn muốn buộc thực thi ngay lập tức, một tùy chọn là kết thúc chuỗi gọi truy vấn bằng ToList ().

Dưới đây là danh sách đầy đủ các toán tử LINQ (theo thứ tự bảng chữ cái) được phân loại theo cách chúng thực thi:

Immediate execution:
Aggregate, All, Any, Average, Contains, Count, ElementAt, ElementAtOrDefault, Empty, First, FirstOrDefault, Last, LastOrDefault, Max, LongCount, Min, SelectMany, SequenceEqual, Single, SingleOrDefault, Sum, ToArray, ToDictionary, ToList, ToLookup.
Deferred execution
AsEnumerable, Cast, Concat, DefaultIfEmpty, Distinct, Except, GroupBy, GroupJoin, Intersect, Join, OfType, OrderBy, OrderByDescending, Range, Repeat, Reverse, Select, SelectMany, Skip, SkipWhile, Take, TakeWhile, ThenBy, ThenByDescending, Union, Where.
Đọc thêm về LINQ trên tài liệu chính thức của Microsoft. 

Post a Comment

أحدث أقدم