C# 2 – Cơ chế yielding và ‘yield’ keyword trong Iteration

“yield” – Một kể từ khóa dường như không quen với các bạn tuy nhiên đã và đang được phần mềm kể từ lâu trong nghề lập trình sẵn và vô không hề ít ngữ điệu. Từ khóa này nối sát với những kinh nghiệm như Generator, Coroutine và những đối tượng người dùng iterator. Ta tiếp tục tò mò chế độ và cơ hội dùng của kể từ khóa này thế nào.

Giới thiệu

Theo MSDN:

Bạn đang xem: C# 2 – Cơ chế yielding và ‘yield’ keyword trong Iteration

The yield keyword signals vĩ đại the compiler that the method in which it appears is an iterator block. The compiler generates a class vĩ đại implement the behavior that is expressed in the iterator block. In the iterator block, the yield keywords is used together with the return keyword vĩ đại provide a value vĩ đại the enumerator object. This is the value that is returned, for example, in each loop of a foreach statement. The yield keyword is also used with break to signal the kết thúc of iteration.

Có thể hiểu giản dị là “yield” tiếp tục kết phù hợp với kể từ khóa “return” được chấp nhận trả về những độ quý hiếm kể từ trong khoảng lặp, và tiếp sau đó nó hoàn toàn có thể quay về vòng lặp và kế tiếp mang lại thành phần tiếp sau.

Điều này khá kì quái tuy nhiên nếu như bạn tiếp tục phát âm những liên kết kể từ Wikimedia vô điều khai mạc thì các bạn sẽ nắm rõ một cơ hội rõ rệt. Điều nhưng mà tôi ham muốn nhắc cho tới ở đấy là “yield return” sẽ không còn thực hiện mang lại công thức chứa chấp nó kết cổ động nhưng mà vẫn kế tiếp chạy cho tới khi kết cổ động vòng lặp và thực thi đua hoàn thành câu mệnh lệnh ở đầu cuối. Muốn kết cổ động công thức các bạn nên sử dụng một cặp kể từ khóa không giống là “yield break”.

Quy định

–       Không bịa đặt “yield” trong số khối unsafe.

–       Các thông số của công thức, toán tử, accessor (getter / setter) ko được sử dụng những kể từ khóa ref hoặc out.

–       “yield return” chỉ hoàn toàn có thể được bịa đặt vô khối try nếu mà nó được theo đòi sau vì thế khối finally.

–       “yield break” hoàn toàn có thể bịa đặt trong số khối trycatch tuy nhiên ko được bịa đặt vô khối finally.

–       Không sử dụng “yield” vô anonymous method.

Cách dùng

Để dùng “yield return”, các bạn chỉ việc tạo nên một công thức với loại trả về là 1 trong những IEnumerable (mảng và collection vô .Net đều implement interface IEnumerable)  với vòng lặp và sử dụng “yield return” nhằm trả về những độ quý hiếm quan trọng vô thân ái vòng lặp.

Ví dụ thay cho viết lách một công thức Foo1() nhằm lấy một mảng int kể từ 0 cho tới một trong những này cơ như bên dưới đây:

public static IEnumerable Foo1(int number)
{
    int[] numbers = new int[number];
    for (int i = 0; i < number; i++)
    {
        numbers[i] = i;
    }
    return numbers;
}

Bạn hoàn toàn có thể thay cho thế công thức bên trên vì thế công thức sau:

public static IEnumerable Foo2(int number)
{
    for (int i = 0; i < number; i++)
    {
        yield return i;
    }
}

Rõ ràng là thay cho trả về vẹn toàn một đối tượng người dùng IEnumerable, tao tiếp tục trả về từng thành phần riêng rẽ lẻ và khi kết cổ động công thức, các bạn không nhất thiết phải return tăng bất kì đối tượng người dùng này.

Bạn hoàn toàn có thể chạy test đoạn mã sau:

Xem thêm: Tây balo là gì? Đặc điểm của hình thức du lịch mới Backpacker

Listing 1:

using System;
using System.Collections;

public class YieldTest
{
    public static IEnumerable Foo2(int number)
    {
        for (int i = 0; i < number; i++)
        {
            yield return i;
        }
    }

    static void Main()
    {
        foreach (var item in Foo2(10))
        {
            Console.Write(item);
        }

        Console.Read();
    }
}

Output:

0123456789

Bạn hoàn toàn có thể bịa đặt break point bên trên dòng sản phẩm 10 và dòng sản phẩm 18 (hai dòng sản phẩm được highlight) và công dụng debug continue (F5) thì tiếp tục thấy rằng nhì break point này tiếp tục thay cho phiên nhau được kích hoạt. Như vậy minh chứng rằng công tác hoàn toàn có thể nhảy tương hỗ thân ái nhì công thức nhưng mà ko làm mất đi hiện trạng lúc này của bọn chúng.

Giả sử mình muốn bay thoát ra khỏi công thức khi i = 5, tao cần thiết sửa lại công thức Foo2() trên:

public static IEnumerable Foo2(int number)
{
    for (int i = 0; i < number; i++)
    {
        if (i == 5)
            yield break;
        yield return i;
    }
}

Ưu điểm

Một điểm mạnh của việc sử dụng “yield” nhưng mà bạn cũng có thể thấy ngay lập tức ở ví dụ trước tiên là con số dòng sản phẩm code sẽ tiến hành giảm xuống.

Hơn nữa, vì thế nhì công thức thao tác luân phiên nhau, các bạn ko quan trọng nên tạo nên hoặc lấy vẹn toàn một list những thành phần nhằm duyệt. Như vậy được vận dụng trong mỗi tình huống như tìm hiểu tìm hiểu, con số thành phần cần thiết duyệt sẽ tiến hành giảm sút tùy từng địa điểm của thành phần cần thiết tìm hiểu.

Cơ chế hoạt động

Trong công thức Foo2() mới mẻ này, các bạn sẽ không sở hữu và nhận thấy sự khác lạ nếu như thay cho yield break vì thế break chính vì khi vòng lặp bị kết cổ động vì thế break thì công thức cũng kết cổ động theo đòi. Muốn đánh giá sự khác lạ, các bạn hãy sử dụng Console.WriteLine() in gì rời khỏi screen ở cuối công thức Foo2() bên trên.

Khi sử dụng ILDasm.exe phân tách Listing 1 tao nhận ra compiler sẽ khởi tạo rời khỏi một tấm con cái vô lớp YieldTest:

YieldTest ILDasm

Hoặc sử dụng một Reflector của hãng sản xuất loại tía nhằm disassemble lớp này rời khỏi mã C# tao được code tổng quát mắng sau:

Xem thêm: Cải thảo tiếng Anh là gì

    private sealed class <Foo2>d__0 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
{
    // Fields
    private int <>1__state;
    private object <>2__current;
    public int <>3__number;
    private int <>l__initialThreadId;
    public int <i>5__1;
    public int number;

    // Methods
    [DebuggerHidden]
    public <Foo2>d__0(int <>1__state);
    private bool MoveNext();
    [DebuggerHidden]
    IEnumerator<object> IEnumerable<object>.GetEnumerator();
    [DebuggerHidden]
    IEnumerator IEnumerable.GetEnumerator();
    [DebuggerHidden]
    void IEnumerator.Reset();
    void IDisposable.Dispose();

    // Properties
    object IEnumerator<object>.Current { [DebuggerHidden] get; }
    object IEnumerator.Current { [DebuggerHidden] get; }
}

Như vậy bạn cũng có thể rằng trên đây thực ra là 1 trong những lớp thao tác dựa vào IEnumertor với những công thức đó là MoveNext(), Reset() và property Current.

Dựa theo đòi cách thức này, bạn cũng có thể đơn giản và dễ dàng thiết lập và tự động đưa đến kinh nghiệm tương tự động “yield” nhằm sử dụng trong số ngữ điệu ko tương hỗ kể từ khóa này ví dụ như VB.Net.

https://goiviettel.vn

BÀI VIẾT NỔI BẬT