*

The Programmable Me


Ở phần 1, bọn họ đã bàn về Functional programing (FP). Ví như như đó là lần đầu các bạn tiếp xúc với có mang này và cảm giác nó cực nhọc hiểu thì cũng đừng sợ, vì ai cũng giống các bạn cả thôi. FP là 1 trong những khái niệm đặc trưng và cũng là một trong những cơ sở nhằm Linq trong .NET được xây dựng. Bởi vì vậy trong quá trình mày mò về Linq, bạn cũng sẽ hiểu rõ được hơn về FP.

Bạn đang xem: Ienumerable c# là gì

Trở lại với Linq, chức năng của C# hỗ trợ bạn thao tác với các tập hòa hợp dữ liệu. Một trong những điều mà lại mình thấy các lập trình viên mắc phải, đó là việc sử dụng Linq không nên quy giải pháp do không hiểu nhiều rõ thực chất của thư viện này. Họ hãy thử quan sát vào định nghĩa của một method Linq điển dường như Where():

public static IEnumerable Where(this IEnumerable source,Func predicate)Như chúng ta thấy, method này được viết dưới dạng “extionsion method”. Đối với phần nhiều ai không biết, “extension method” là 1 trong những tính năng của C# nhằm giúp không ngừng mở rộng thêm những method cho class hoặc interface của doanh nghiệp bằng việc viết nó dưới dạng “static” tại một class không giống và thực hiện từ khóa “this”. Ở method trên, chúng ta cũng có thể thấy rằng, interface được mở rộng là IEnumerable. Nếu khách hàng đã đọc kĩ phần trước, các bạn sẽ biết rằng IEnumerable là interface đa phần được Linq hướng đến.Vì vậy để hiểu rõ Linq thì chúng ta cần nắm vững về interface này.

IEnumerable cùng từ khóa yield return

IEnumerable được quan niệm trong System.Collection.Generics và là một interface vô cùng đối kháng giản:

public interface IEnumerable IEnumerator GetEnumerator();Như bạn thấy, interface này chỉ có một method duy nhất, GetEnumerator(), trả về một giá chỉ trị tất cả dạng IEnumerator. IEnumerator được khái niệm như sau:

public interface IEnumerator T Currentget; void Dispose(); bool MoveNext(); void Reset();Nhìn vào hai interface trên, cứng cáp hẳn chúng ta cũng đoán được ý nghĩa sâu sắc của chúng. IEnumerator chất nhận được bạn tiến hành đọc qua tất cả các cực hiếm trong một tập hợp. Hãy tưởng tượng bạn đang muốn đọc và xử lý những dòng trong một bảng biểu, khi bạn có nhu cầu đọc sang tài liệu tiếp theo, bạn gọi MoveNext() cùng đọc dữ liệu đó qua ở trong tính Current. Khi không còn dữ liệu nữa, MoveNext() sẽ trả về false. Bạn có thể đọc lại từ đầu bằng method Reset(), hoặc xóa khỏi cả tập hợp bởi Dispose()

IEnumerable là interface cơ bạn dạng nhất đại diện thay mặt cho những kiểu tập hợp dữ liệu trong C#, vì nó khái niệm những hào kiệt cơ bạn dạng nhất mà lại một tập hợp cần có: kỹ năng đọc các phần tử một bí quyết lần lượt. Toàn bộ các class dùng làm chứa các tập hợp tài liệu (Dictionary, Collection, ArrayList, List…) đều thừa kế từ interface này. IEnumerable cũng là interface được cho phép bạn call từ khóa foreach , về cơ bạn dạng chính là 1 trong những vòng lặp mà tự động hóa gọi MoveNext() và Current

Việc tiến hành interface này khá 1-1 giản: chúng ta cũng có thể viết một linked-list để đựng dữ liệu, bởi vì linked-list cũng có thể chấp nhận được truy cập bộ phận một giải pháp lần lượt như vậy. Tuy vậy trong C#, bọn họ có một giải pháp viết khác để tự động xây dựng một kết cấu dữ liệu hình dạng IEnumerable, sẽ là việc thực hiện từ khóa yield return.

Cách cực tốt để hiểu được tự khóa này là cần sử dụng ví dụ:

IEnumerable generateString() yield return "one"; yield return "two"; yield return "three";Hàm generateString() ko gọi bất cứ class nào kế thừa từ IEnumerable cả, mà dùng từ khóa yield return. Khi 1 hàm sử dụng từ khóa này, hàm này được gọi là “Generator”. Lúc hàm này chạm mặt từ khóa “yield return“, nó sẽ dứt hoạt cồn và gửi giá trị được yield kia vào chuỗi IEnumerable cơ mà nó trả về. Bây giờ tại hàm gọi Generator đó, bạn có thể đọc được ngay giá bán trị trước tiên đó. Khi bạn có nhu cầu đọc giá trị tiếp theo(bằng cách dùng foreach hoặc điện thoại tư vấn MoveNext()), Generator sẽ tiếp tục chạy từ địa chỉ yield return cũ cho đến từ khóa yield return tiếp theo. Những lần điện thoại tư vấn giá trị sau cũng diễn ra y hệt như vậy. Đến lúc hàm này không gặp mặt từ khóa yield return làm sao nữa(hoặc khi nó gặp gỡ từ khóa yield break) thì chuỗi IEnumerable trả về sẽ tiến hành hoàn tất (đây là lúc cơ mà MoveNext() trả về false)

Để dễ dàng nắm bắt hơn, hãy đọc ví dụ sau đây.

private static IEnumerable generateStrings() Console.WriteLine("yield one"); yield return "one"; Console.WriteLine("yield two"); yield return "two"; Console.WriteLine("yield three"); yield return "three";//codevar seq = generateStrings();foreach(string s in seq) Console.WriteLine($"loop i++"); Console.WriteLine(s);//output//yield one//loop 1//one//yield two//loop 2//two//yield three//loop 3//threeBạn có thể thấy là hàm generateStrings() chỉ tiếp tục chạy lúc vòng lặp foreach đưa sang giá chỉ trị tiếp theo của chuỗi IEnumerable. Đây là vấn đề làm phải điểm hay tuyệt nhất của IEnumerable: lazy evaluation, tức là chỉ thực hiện giám sát và trả về dữ liệu khi được gọi. Ứng dụng của tác dụng này là rất lớn: Hãy tưởng tượng các bạn đang thao tác làm việc với một nguồn dữ liệu khổng lồ, được gọi từ 1 nguồn dữ liệu nào kia (database, network…). Bạn không muốn gọi tất cả các dữ liệu đó cùng lúc, vị nó quá to và vượt mất thời gian, mà cầm vào kia là call chúng một phương pháp lần lượt. Khi bạn không muốn liên tiếp gọi dữ liệu nữa, bạn cũng có thể ngừng Generator đó lại bằng những gọi yield break ở bên phía trong hàm generator, hoặc điện thoại tư vấn Dispose() làm việc IEnumerator của IEnumerable mà chúng ta nhận được. Hình dáng như sau:

IEnumerable getRecords() int i=0; while(true) Record record = ReadRecord(i++); yield return record; void Process() var records = getRecords(); var enumerator = records.GetEnumerator(); while(enumerator.MoveNext()) ProcessResult result = ProcessRecord(enumerator.Current); if (result == ProcessResult.Enough) enumerator.Dispose(); return; Nếu các bạn thấy phần nhiều điều trên là rất khó hiểu thì cũng không có gì đáng sợ hãi cả, vày generator là 1 khái niệm kha khá khó gắng bắt. Cách rất tốt để phát âm được nó là hãy mở Visual Studio lên với bỏ thời gian nghịch ngợm một chút.

Hàm Where trong Linq

Giờ thì chắc chúng ta cũng thâu tóm được kha khá về IEnumerable rồi (nếu như không thì lời khuyên của bản thân là nên ngừng đọc với dành chút thời hạn để test nghiệm). Chúng ta hãy test dùng vấn đề này để viết lại một hàm đơn giản và dễ dàng nhất vào Linq: Where (xem tư tưởng hàm này sống đầu bài)

Hàm Where về cơ bản có tác dụng giống như 1 filter(tương từ bỏ như câu “WHERE” trong sql). Nó giúp cho bạn chọn thanh lọc ra những thành phần trong một tập hợp mà vừa lòng một yêu mong nào đó. Họ hãy quay trở về ví dụ cùng với hàm generateStrings() sẽ viết sinh hoạt trên(đã đào thải các đoạn Console.WriteLine()). Trả sử bạn muốn chọn thanh lọc ra phần đông string bao gồm độ dài nhỏ dại hơn 4 (trong trường hợp trên là “one” cùng “two”). Các bạn hoàn toàn có thể viết như sau

public static class MyLinq{ public static IEnumerable Where(this IEnumerable source) { foreach(string s in source) { if(s.LengthĐiều này còn có nghĩa rằng chỉ các đoạn quý hiếm string nào tất cả độ dài nhỏ dại hơn 4 mới được hàm này chào đón và đưa vào cực hiếm IEnumerable đầu ra.

Xem thêm: Giải Bài 6 Trang 140 Sgk Toán 10, Bài 6 Trang 140 Sgk Đại Số 10

Đoạn code trên vận động hoàn toàn đúng, xung quanh trừ vấn đề nó không có tính tái thực hiện cho lắm: bạn không tinh chỉnh được logic lựa lựa chọn của hàm Where, với hàm Where hiện tại chỉ vận động với loại string cơ mà thôi. Chúng ta có đừng quên trong phần trước, bọn họ có kể tới việc C# cung cấp kiểu dữ liệu Func. Bọn họ hãy viết lại hàm Where nhằm tận dụng điều này:

public static class MyLinq public static IEnumerable Where(this IEnumerable source, Func predicate) foreach(T tòa tháp in source) if (predicate(item)) yield return s; //codevar source = generateStrings();var seq = source.Where(s=> s.Length tiếng thì hàm Where của chúng ta đã tương đối giống với hàm Where trong Linq rồi. Nó cho phép bạn call hàm này với bất kì kiểu dữ liệu nào, còn chỉ ra ngắn gọn xúc tích lựa lựa chọn tại thời gian gọi hàm. Trên thực tế, đoạn code này về cơ phiên bản là như là với hàm Where thực sự trong Linq(ngoại trừ một vài xúc tích kiểm tra điều kiện). Tuyệt!

Nếu tinh ý thì bạn cũng trở thành nhận ra rằng hàm Where của họ là một hàm “thuần” (pure function), tức là nó không làm đổi khác dữ liệu. Điều này đúng cho toàn bộ các hàm trong Linq (tất nhiên, để nó thực sự “thuần”, thì bạn dạng thân xúc tích trong hàm “predicate” cũng không được làm đổi khác gì về dữ liệu). Một điểm độc đáo nữa của hàm Where là nó là 1 trong những hàm “lười” (lazy function), có nghĩa là tại thời điểm bạn điện thoại tư vấn Where(), không có bất cứ logic chọn lọc nào được thực hiện. Chỉ khi chúng ta tìm bí quyết đọc thành phần của chuỗi IEnumerable mà Where() trả về, thời điểm đó logic “predicate” của bạn mới ban đầu hoạt động.