Yineleyiciler

Öğeleri çağıran kodun bir koleksiyonda tam sonucu oluşturmadan birer birer kullanabileceği bir sekans döndürmek istediğinizde bir yineleyici seçin. Bu yaklaşım, oluşturulan değerler, özel denetim akışına sahip filtreler ve çağıranların okumayı erkenden bırakabileceği diziler için uygundur. Tamamlanmış bir koleksiyonla karşılaştırıldığında, bir yineleyici yalnızca onu nasıl yazdığınızı değil, işin ne zaman gerçekleştiğini de değiştirir.

Tip

Bu makale, yöntemleri, döngüleri ve koleksiyonları bilen geliştiriciler için eşzamanlı yineleyicileri öğretir. Tam yield söz dizimi ve kısıtlamalar için yield ifade başvurusuna bakın.

Yineleyici yöntemi değerleri tek tek üretir. Bu makale, çağıranların genellikle IEnumerable<T> deyimiyle kullandığı değerleri döndüren foreach yineleyici yöntemlerine odaklanır.

yield return ile öğeler oluşturun

yield return dizideki sonraki öğeyi sağlamak için kullanın. Aşağıdaki yineleyici, bir sensörden kabul edilebilir sıcaklık okumalarını seçer. Bu senaryoda, -1 algılayıcı verilerinin sonunu işaretler.

int[] readings = [21, 27, 24, -1, 19];

IEnumerable<int> acceptedReadings =
    SelectTemperatures(readings, maximum: 25);

Console.WriteLine("Sequence created.");

foreach (int temperature in acceptedReadings)
{
    Console.WriteLine($"Accepted: {temperature}°C");
}

static IEnumerable<int> SelectTemperatures(
    IEnumerable<int> readings,
    int maximum)
{
    foreach (int reading in readings)
    {
        Console.WriteLine($"Checking {reading}°C");

        if (reading == -1)
        {
            yield break;
        }

        if (reading <= maximum)
        {
            yield return reading;
        }
    }
}

SelectTemperatures, IEnumerable<int> değerlerinden oluşan bir diziyi temsil eden int değerini döndürür. yield return reading Her biri foreach döngüsüne bir değer sağlar. Çağıran bu değeri işledikten sonra yineleyici sonraki girişle devam eder.

Çoğu modern C# kodu için genel IEnumerable<T> formunu kullanın. int gibi tür bağımsız değişkeni, çağıranlara dizinin hangi öğe türünü içerdiğini söyler.

Sırayı şu şekilde sonlandırın: yield break

Yineleyiciyi, akış yöntemin sonuna ulaşmadan önce sonlandırmak için yield break kullanın. Örnekte sentinel değeri -1, başka okuma olmadığı anlamına gelir:

if (reading == -1)
{
    yield break;
}

Yineleyici ayrıca yürütme gövdesinin sonuna ulaştığında doğal olarak sona erer. Bir koşulun öğe üretimini hemen durdurması gerektiğinde kullanın yield break .

Bir yineleyiciyi tüketme foreach

Yineleyici, birçok .NET koleksiyonuyla aynı IEnumerable<T> yapıyı kullanıma sunar. Çağıranlar, dizinin öğelerini nasıl ürettiğini bilmeden foreach kullanabilir:

foreach (int temperature in SelectTemperatures(readings, 25))
{
    Console.WriteLine($"Accepted: {temperature}°C");
}

Çağıran, döngü ilerledikçe her öğeyi istemektedir. Yineleyici, istekler arasındaki konumunu korur ve önceki yield return öğesinden sonra devam eder.

Ertelenen öğe oluşturmayı anlama

Yineleyici yöntemini çağırmak, gövdesini hemen çalıştırmaz. Çağıran yinelemeye başladığında yöntem öğeler üretmeye başlar. Bu davranış ertelenmiş yürütme olarak adlandırılır.

Örnek, herhangi bir Sequence created. iletisinden önce Checking ... yazdırır. Yineleyici yalnızca foreach döngü ilk öğesini istediğinde okumaları denetlemeye başlar.

Gecikmeli yürütmenin pratik etkileri vardır:

  • Çağıran, yineleyici her öğeyi üretmeden önce işlemeye başlayabilir.
  • Yineleyici, yield break ile erken durabilir.
  • Sıralamayı hiçbir zaman yinelemeyen bir çağıran kod yineleyici gövdesini çalıştırmaz.
  • Her yeni enumarasyon yineleyiciyi yeniden çalıştırır.

Yöntemin amacında ve belgelerinde ertelenmiş yürütmeyi net hale getirin. Hem yineleyiciler hem de koleksiyonlar da bu arabirimi sunabildiği için okuyucular yürütme zamanlamasını yalnızca IEnumerable<T> ifadesinden çıkaramaz. Çağıranlar diziyi daha sonra veya birden çok kez numaralandırabileceğinden, öğe üretimini ilgisiz yan etkilerden arındırın. Örneğe ait tanılama iletileri bu zamanlamayı gösterir.

Yineleyici veya koleksiyon seçin

Değerler doğal olarak birer birer geldiğinde veya çağıranın hemen tam sonuca ihtiyacı olmadığında bir yineleyici döndürün. Çağıranların öğeleri yeniden hesaplamadan kararlı bir anlık görüntüye, dizine alınan erişime veya yinelenen yinelemeye ihtiyacı olduğunda tamamlanmış bir koleksiyon döndürür.

Her iki yaklaşım da aynı öğeleri döndürebilir. Yineleyici, öğe üretimini çağıranın denetimi altında bırakır; koleksiyonu oluşturan bir yöntem, dönmeden önce bu işi tamamlar.

Sıra döndürmeden her öğe için bir eylem gerçekleştirmek istediğinizde normal bir döngü kullanın. Standart bir filtre veya dönüştürme için, örneğin Select veya Where gibi bir LINQ işlemini tercih edin; özel öğe üretim mantığı bir dizi deyim olarak daha net olduğunda yineleyici yazın.

Yineleyici yöntemleri LINQ ile birleşir çünkü her ikisi de IEnumerable<T> kullanır. Örneğin, arayan başka bir filtre ekleyebilir:

var comfortableReadings = SelectTemperatures(readings, 25)
    .Where(static temperature => temperature >= 18);

Yineleyici ve LINQ işlemi, kod comfortableReadings üzerinde yineleme yapana kadar ertelenmiş olarak kalır.

Zaman uyumsuz diziler için bkz. Zaman uyumsuz akışlar oluşturma ve kullanma. Özel numaralandırma desenleri ve tüm yield kısıtlamaları için dil referansını kullanın.

Ayrıca bkz.