Bilineceği üzere bir class ın foreach iterasyonuna sahip olabilmesi için IEnumerable interfacesini implement etmesi gerekmekte. IEnumerable 'ı implemente eden class bu implementle birlikte override edilmesi gereken GetEnumerator metoduna sahip olur ve bu metodun içerisini doldurduktan sonra artik bu class da foreach ile gezebilecek duruma gelir. GetEnumerator metodunu override ederken, MoveNext(), Reset() metotlarini ve Current isimli propertyleri ile ilgili logic'i handle etmemiz gerekiyordu. İşte yield sayesinde bunları yapmaktan kurtuluyoruz.
Mantigi oldukca basit ama bazi projelerde uygulamaya entegrasyonu sıkıntı çıkarabiliyor. Iste bu sıkıntıları gidermek için C# 2.0 ile birlikte gelen yield keywordu sayesinde bu işlemlerin tumu bizim için arka planda yapilmis olacak.
Senaryomuz şu şekilde olsun; geriye db de kayıtlı olan ürünleri dönen bir metodumuz var ve bu metodu yield kullanmadan ve yield kullanarak yazmaya çalışalım.
Yield kullanmadan
public static IEnumerable<Product> GetAllProducts()
{
using (var db = new DbEntity())
{
var productList = from product in db.Product
select product;
return productList.ToList();
}
}
Bu normal şartlarda kullandığımız yöntem. İlgile metodu aşağıdaki gibi çağırıp dönen listeye direk olarak erişebilirsiniz.
var productList = GetAllProducts();
yield kullanarak ise şu şekilde yazabiliriz
Yield Kullanarak
public static IEnumerable<Product> GetAllProducts()
{
using (var db = new DbEntity())
{
var productList = from product in db.Product
select product;
foreach (var item in productList)
{
yield return product;
}
}
}
yield da ise şu şekilde çalışır;
döngüye her girdiğinde yield return product satırında fonksiyonun çağrıldığı yere ilgili product item'ını döner yani return'ü gördü diye foreach den ve metoddan direkt çıkmaz ve listenin içindeki tüm elemanlar bitinceye kadar bu işlemi yapmaya devam eder.
IL Disassambler(ILDASM) acarak code tarafında MoveNext,Reset ve Current gibi uyeler yazmamamiza ragmen yield keywordu sayesinde arka planda bunlarin yazildigini goruyoruz.
Bir diğer örnek olarak ise şunu verebiliriz;
public void Consumer()
{
foreach(int i in Integers())
{
Console.WriteLine(i.ToString());
}
}
public IEnumerable<int> Integers()
{
yield return 1;
yield return 2;
yield return 4;
yield return 8;
yield return 16;
yield return 45;
}
Foreach de dönerken her bir int i için IEnumerable<int> Integers() metoduna giderek değerleri bize teker teker döndürebiliyor.