yield deyimi - sonraki öğeyi sağlayın

Yineleme sırasında bir diziden sonraki değeri sağlamak için yineleyicide deyimini kullanırsınızyield. deyimi yield aşağıdaki iki biçime sahiptir:

  • yield return: aşağıdaki örnekte gösterildiği gibi yinelemede bir sonraki değeri sağlamak için:

    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: aşağıdaki örnekte gösterildiği gibi yinelemenin sonunu açıkça göstermek için:

    Console.WriteLine(string.Join(" ", TakeWhilePositive(new[] { 2, 3, 4, 5, -1, 3, 4})));
    // Output: 2 3 4 5
    
    Console.WriteLine(string.Join(" ", TakeWhilePositive(new[] { 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;
            }
        }
    }
    

    Denetim yineleyicinin sonuna ulaştığında da yineleme tamamlar.

Önceki örneklerde yineleyicilerin dönüş türü şöyledir IEnumerable<T> (genel olmayan durumlarda yineleyicinin dönüş türü olarak kullanın IEnumerable ). Yineleyicinin dönüş türü olarak da kullanabilirsiniz IAsyncEnumerable<T> . Bu, yineleyiciyi zaman uyumsuz hale getirir. await foreach Aşağıdaki örnekte gösterildiği gibi yineleyicinin sonucunu yinelemek için deyimini kullanın:

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> veya IEnumerator yineleyicinin dönüş türü de olabilir. Bu, aşağıdaki senaryolarda yöntemini uyguladığınızda GetEnumerator yararlıdır:

  • Veya IEnumerable arabirimini uygulayan türü tasarlarsınızIEnumerable<T>.

  • Aşağıdaki örnekte gösterildiği gibi deyimiyleforeach türün örneği üzerinde yinelemeyi etkinleştirmek için bir örnek veya uzantıGetEnumerator yöntemi eklersiniz:

    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;
        }
    }
    

Deyimlerini şu şekilde kullanamazsınız yield :

Yineleyici yürütme

Aşağıdaki örnekte gösterildiği gibi yineleyici çağrısı hemen yürütülmüyor:

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.

Yukarıdaki örnekte gösterildiği gibi, yineleyicinin sonucunu yinelemeye başladığınızda, ilk yield return deyime ulaşılana kadar yineleyici yürütülür. Ardından, bir yineleyicinin yürütülmesi askıya alınır ve çağıran ilk yineleme değerini alır ve işler. Sonraki her yinelemede, bir yineleyicinin yürütülmesi önceki askıya alınmaya yield return neden olan deyiminden sonra devam eder ve bir sonraki yield return deyime ulaşılana kadar devam eder. Denetim bir yineleyicinin veya yield break deyimin sonuna ulaştığında yineleme tamamlar.

C# dili belirtimi

Daha fazla bilgi için C# dil belirtimininödeme deyimi bölümüne bakın.

Ayrıca bkz.