C# - C Sharp: yield


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Bạn sử dụng câu lệnh yield trong một trình vòng lặp để cung cấp giá trị tiếp theo hoặc báo hiệu sự kết thúc của một vòng lặp. Câu lệnh yield có hai hình thức sau:

yield return

yield return để cung cấp giá trị tiếp theo trong lần lặp, như ví dụ sau:

foreach (int i in ProduceEvenNumbers(9))
{
    Console.Write(i);
    Console.Write(" ");
}
// Output: 0 2 4 6 8

IEnumerable<int> ProduceEvenNumbers(int upto)
{
    for (int i = 0; i <= upto; i += 2)
    {
        yield return i;
    }
}

yield break:

yield break để báo hiệu một cách tường minh sự kết thúc của vòng lặp, như ví dụ sau:

Console.WriteLine(string.Join(" ", TakeWhilePositive([2, 3, 4, 5, -1, 3, 4])));
// Output: 2 3 4 5

Console.WriteLine(string.Join(" ", TakeWhilePositive([9, 8, 7])));
// Output: 9 8 7

IEnumerable<int> TakeWhilePositive(IEnumerable<int> numbers)
{
    foreach (int n in numbers)
    {
        if (n > 0)
        {
            yield return n;
        }
        else
        {
            yield break;
        }
    }
}

Việc lặp lại cũng kết thúc khi điều khiển đạt đến cuối vòng lặp.

Trong các ví dụ trên, kiểu trả về của trình vòng lặp là IEnumerable<T> (trong các trường hợp non-generic, hãy sử dụng IEnumerable làm kiểu trả về của trình vòng lặp). Bạn cũng có thể sử dụng IAsyncEnumerable<T> làm kiểu trả về của trình vòng lặp. Điều đó làm cho một trình vòng lặp không đồng bộ. Sử dụng câu lệnh await foreach để lặp lại kết quả của iterator, như ví dụ sau cho thấy:

await foreach (int n in GenerateNumbersAsync(5))
{
    Console.Write(n);
    Console.Write(" ");
}
// Output: 0 2 4 6 8

async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
    for (int i = 0; i < count; i++)
    {
        yield return await ProduceNumberAsync(i);
    }
}

async Task<int> ProduceNumberAsync(int seed)
{
    await Task.Delay(1000);
    return 2 * seed;
}

IEnumerator<T> hoặc IEnumerator cũng có thể là kiểu trả về của trình vòng lặp. Điều đó rất hữu ích khi bạn triển khai phương thức GetEnumerator trong các trường hợp sau:

  • Bạn thiết kế kiểu triển khai giao diện IEnumerable<T> hoặc IEnumerable.

  • Bạn thêm một phiên bản hoặc phương thức mở rộng GetEnumerator để cho phép lặp qua phiên bản của kiểu đó bằng câu lệnh foreach, như ví dụ sau đây cho thấy:

public static void Example()
{
    var point = new Point(1, 2, 3);
    foreach (int coordinate in point)
    {
        Console.Write(coordinate);
        Console.Write(" ");
    }
    // Output: 1 2 3
}

public readonly record struct Point(int X, int Y, int Z)
{
    public IEnumerator<int> GetEnumerator()
    {
        yield return X;
        yield return Y;
        yield return Z;
    }
}

Bạn không thể sử dụng các câu lệnh yield trong:

Thực thi một iterator

Lệnh gọi của một trình vòng lặp không thực hiện nó ngay lập tức, như ví dụ sau đây cho thấy:

var numbers = ProduceEvenNumbers(5);
Console.WriteLine("Caller: about to iterate.");
foreach (int i in numbers)
{
    Console.WriteLine($"Caller: {i}");
}

IEnumerable<int> ProduceEvenNumbers(int upto)
{
    Console.WriteLine("Iterator: start.");
    for (int i = 0; i <= upto; i += 2)
    {
        Console.WriteLine($"Iterator: about to yield {i}");
        yield return i;
        Console.WriteLine($"Iterator: yielded {i}");
    }
    Console.WriteLine("Iterator: end.");
}
// Output:
// Caller: about to iterate.
// Iterator: start.
// Iterator: about to yield 0
// Caller: 0
// Iterator: yielded 0
// Iterator: about to yield 2
// Caller: 2
// Iterator: yielded 2
// Iterator: about to yield 4
// Caller: 4
// Iterator: yielded 4
// Iterator: end.

Như ví dụ trên cho thấy, khi bạn bắt đầu lặp lại kết quả của một trình vòng lặp, một trình vòng lặp sẽ được thực thi cho đến khi yield return đạt đến câu lệnh đầu tiên. Sau đó, việc thực thi một trình lặp bị tạm dừng và người gọi sẽ nhận giá trị lặp đầu tiên và xử lý nó. Ở mỗi lần lặp tiếp theo, việc thực thi của một trình vòng lặp sẽ tiếp tục sau câu lệnh yield return gây ra sự tạm dừng trước đó và tiếp tục cho đến khi yield return đạt được câu lệnh tiếp theo. Việc lặp lại hoàn thành khi điều khiển đạt đến cuối một trình vòng lặp hoặc một câu lệnh yield break.

Đặc tả ngôn ngữ C#

Để biết thêm thông tin, hãy xem phần câu lệnh yield của đặc tả ngôn ngữ C#.

Xem thêm

» Tiếp: record
« Trước: using
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!