Linq Series 7- Sử dụng IEnumerable và Method Chaining trong Linq

Linq Series 7- Sử dụng IEnumerable và Method Chaining trong Linq

Chia sẻ kiến thức 16/04/2023

Sử dụng IEnumerable và Method Chaining trong Linq

Xin chào các bạn, trong bài trước chúng ta đã đề cập tới 2 khái niệm là Fluent API và Method Chaining là hai khái niệm thường được sử dụng trong lập trình hướng đối tượng để tăng tính tổ chức, đơn giản hóa cú pháp và làm cho mã (code) dễ đọc hơn. Chúng ta cũng đã đề cập tới ứng dụng thực tế của Method Chaining đối với Linq. Hôm nay mình sẽ đi sâu về mối liên hệ giữa IEnumerable và Method Chaining trong Linq.

Mối liên hệ giữa IEnumerable và Method Chaining trong cú pháp truy vấn Linq

Trong bài trước, chúng ta đã biết rằng hầu hết các phương thức của LINQ là các phương thức mở rộng cho
kiểu IEnumerable(T).

Trong bài này, chúng ta sẽ xem xét kỹ hơn về kiểu này vì hiểu được một số tính năng của LINQ là rất quan trọng. IEnumerable(T) là một interface được triển khai bởi hầu hết các collection trong C# : Array, List, HashSet, Dictionary. Chúng đều được triển khai bởi IEnumerable<T> interface.

Như chúng ta đã nói trước đây, hầu hết các phương thức của LINQ là các phương thức mở rộng cho IEnumerable(T).
Điều đó có nghĩa là chúng ta có thể sử dụng chúng với bất kỳ loại nào triển khai interface IEnumerable(T).Điều này rất tiện dụng.Sẽ không thành vấn đề nếu collection mà chúng ta làm việc là một mảng,danh sách hoặc Hàng đợi, LINQ sẽ làm việc với chúng như nhau.

Một điều quan trọng khác cần biết về IEnumerable là nó không hiển thị bất kỳ phương thức nào của sự thay đổi collection. Điều đó có nghĩa là các phương thức LINQ sẽ không bao giờ sửa đổi các input collection vì đơn giản là chúng không có phương tiện để làm như vậy. Không có một phương thức nào cho với sự thay đổi của collection trong IEnumerable interface

Việc LINQ không bao giờ sửa đổi các collection đầu vào có thể hơi ngạc nhiên, đặc biệt nếu bạn biết rằng LINQ cung cấp các phương thức như Append()để thêm một phần tử vào cuối tập hợp. Tuy nhiên, collection  ban đầu sẽ không được sửa đổi bằng phương pháp này. Một bộ sưu tập mới có phần tử bổ sung sẽ được tạo ra.

Bắt đầu thực hành code để hiểu vấn đề thôi. Đầu tiên tạo một đoạn code có sử dụng hàm Append() như sau

        private static void test_1()
        {
            var numbers = new List<int> { 5, 3, 7, 1, 2, 4 };
            var numbersWith10 = numbers.Append(10);
            Console.WriteLine("Numbers: " + string.Join(", ", numbers));
            Console.WriteLine("Numbers with 10: " + string.Join(", ", numbersWith10));

        }

Kết quả chạy :

Như bạn có thể thấy, bộ sưu tập số chưa được sửa đổi, số 10 vẫn chưa có. Một bộ sưu tập mới với 10 ở cuối đã được tạo.
Bất cứ khi nào LINQ thực hiện một thao tác tạo một bộ sưu tập mới, nó sẽ trả về nó dưới dạng IEnumerable(T).

Như ở hình thì biến numbersWith10 có kiểu dữ liệu là IEnumerable<int>

Có nhiều phương thức để tạo ra các collection mới trong LINQ.

Ví dụ: có phương thức Where lọc tập hợp hoặc phương thức OrderBy sắp xếp tập hợp đó.

public static IEnumerable<TSource> Where<TSource>
              (this IEnumerable<TSource> source,Func<TSource, bool> predicate);

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>
              (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);

They both produce the result as an IEnumerable(T), and they don’t modify the input collection.

Cả 2 phương thức đều có kết quả trả về là IEnumerable<T> và chúng sẽ không thay đổi nội dung của collection tham số đầu vào.

Vì vậy chúng ta có 2 tính năng của các phương thức Linq và cả 2 chúng đều có hiệu ứng rất thú vị. Đầu tiên là Linq sử dụng IEnumerable<T> như một tham số đầu vào. Điều thứ hai là phương thức đó trả về cũng là kiểu IEnumerable<T>. Tham số đầu vào và kết quả trả về đều cùng một kiểu.

Điều đó có nghĩa là chúng ta có thể thực thi một phương thức Linq để lấy kết quả và phương thức Linq khác sử dụng kết quả đó.

Hãy xem tiếp ví dụ thực hành sau đây : 

var oddNumbers = numbers.Where(number => number % 2 == 1);
var orderedOddNumbers = oddNumbers.OrderBy(number => number);
Console.WriteLine("OrderedOddNumbers: " + string.Join(", ", orderedOddNumbers));

Ở dòng đầu tiên,chúng ta sử dụng phương thức Where() để lọc mảng numbers ra các số lẻ. Ở dòng tiếp theo, chúng ta sử dụng phương thức OrderBy() để sắp xếp dãy số theo thứ tự tăng dần.

Kết quả của collection sau cùng là orderedOddNumbers là sự kết hợp kết quả trả về của 2 phương thức. Nó có  chứa danh sách các số lẻ đã được sắp xếp.

Thực hiện chương trình ta có kết quả như sau : 

Tiếp theo chúng ta sẽ tối ưu hóa đoạn code hơn bằng cách xóa đi giá trị biến oddNumbers và sử dụng phương thức Where() trực tiếp vào biến phía sau như đoạn code đây :

  var orderedOddNumbers = numbers
.Where(number => number % 2 == 1)
.OrderBy(number => numbers);

Cách gọi phương thức liên tiếp như trên được gọi là Method Training .

Tài liệu tham khảo

  1. https://github.com/vupt172/linq-series/tree/linq-series-6
ĐĂNG KÝ TƯ VẤN HỌC LẬP TRÌNH TẠI FUNiX

Bình luận (
0
)

Bài liên quan

  • Tầng 0, tòa nhà FPT, 17 Duy Tân, Q. Cầu Giấy, Hà Nội
  • info@funix.edu.vn
  • 0782313602 (Zalo, Viber)        
Chat Button
Chat với FUNiX GPT ×

yêu cầu gọi lại

error: Content is protected !!