Aracılığıyla paylaş


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

yield Sonraki değeri sağlamak veya yinelemenin sonuna işaret etmek için yineleyicide deyimini kullanın. 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 işaret etmek için:

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

    Yineleme, denetim yineleyicinin sonuna ulaştığında da tamamlar.

C# dili başvuru belgesi, C# dilinin en son yayımlanan sürümünü gösterir. Ayrıca, yaklaşan dil sürümü için genel önizlemelerdeki özelliklere yönelik ilk belgeleri içerir.

Belgelerde ilk olarak dilin son üç sürümünde veya geçerli genel önizlemelerde sunulan tüm özellikler tanımlanır.

Tavsiye

Bir özelliğin C# dilinde ilk tanıtıldığı zamanları bulmak için C# dil sürümü geçmişi makalesine bakın.

Yukarıdaki örneklerde yineleyicilerin dönüş türü şeklindedir 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, bir yineleyiciyi zaman uyumsuz yapar. 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. Aşağıdaki senaryolarda yöntemini uygularken GetEnumerator bu dönüş türlerini kullanın:

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

  • Aşağıdaki örnekte gösterildiği gibi deyimiyletürün örneği üzerinde yinelemeyi etkinleştirmek için bir örnek veya GetEnumeratorforeach 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 :

  • içindeyöntemleri, referansveya dışa alınan parametreleri.
  • lambda ifadeleri ve anonim yöntemler.
  • güvenli olmayan bloklar. C# 13'e geçmeden önce, yield bir bloğu olan herhangi bir unsafe yöntemde geçersizdi. C# 13'le başlayarak bloklu yield yöntemlerde kullanabilirsiniz unsafe ancak blokta unsafe kullanamazsınız.
  • yield returnve yield breakcatch ve finally bloklarında veya karşılık gelen bir blokla catch bloklarında kullanılamaz. yield return ve yield break deyimleri blok içermeyen try bir blokta, yalnızca bir catchfinally blokta kullanılabilir.

using yineleyicilerdeki deyimler

Yineleyici yöntemlerinde deyimleri kullanabilirsinizusing. using Deyimler yan tümcelerle finally (ve blok olmadancatch) bloklar halinde try derlendiğinden, yineleyicilerle doğru şekilde çalışır. Atılabilir kaynaklar yineleyicinin yürütülmesi boyunca düzgün bir şekilde yönetilir:

Console.WriteLine("=== Using in Iterator Example ===");

// Demonstrate that using statements work correctly in iterators
foreach (string line in ReadLinesFromResource())
{
    Console.WriteLine($"Read: {line}");
    // Simulate processing only first two items
    if (line == "Line 2") break;
}

Console.WriteLine("Iteration stopped early - resource should still be disposed.");

static IEnumerable<string> ReadLinesFromResource()
{
    Console.WriteLine("Opening resource...");
    using var resource = new StringWriter(); // Use StringWriter as a simple IDisposable
    resource.WriteLine("Resource initialized");
    
    // These lines would typically come from the resource (e.g., file, database)
    string[] lines = { "Line 1", "Line 2", "Line 3", "Line 4" };
    
    foreach (string line in lines)
    {
        Console.WriteLine($"About to yield: {line}");
        yield return line;
        Console.WriteLine($"Resumed after yielding: {line}");
    }
    
    Console.WriteLine("Iterator completed - using block will dispose resource.");
}

Yukarıdaki örnekte gösterildiği gibi, yineleyici deyimlerde yürütmeyi usingyield return askıya alıp sürdürse bile, deyiminde alınan kaynak yineleyicinin yürütmesi boyunca kullanılabilir durumda kalır. Kaynak, yineleyici tamamlandığında (sona ulaşılarak veya aracılığıyla yield break) veya yineleyicinin kendisi atıldığında (örneğin, çağıranın numaralandırması erken sonlandırıldığında) atılır.

Yineleyici yürütme

Aşağıdaki örnekte gösterildiği gibi bir yineleyici çağrılması 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, yineleyici ilk yield return deyime ulaşılana kadar yürütülür. Ardından 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, yineleyicinin yürütülmesi önceki askıya alma işlemine yield return neden olan deyimden sonra devam eder ve 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.