C# 8.0 – IAsyncEnumerable<T> ve IAsyncEnumerator<T> Arayüzleri İle Asenkron Iterasyonel İşlev Oluşturma

Merhaba,

Önceki C#’ta IEnumerable ve IEnumerator Interfaceleri Nedir? ve Nasıl Kullanılır? başlıklı makalemde IEnumerable ve IEnumerator interfaceleri üzerine uzun uzun konuşmuştuk. Bu içeriğimizde ise ilgili interfacelerin asenkron altyapıda şekillendirildiği C# 8.0 ile gelen yeni hallerini(IAsyncEnumerable<T> ve IAsyncEnumerator<T>) konuşacağız.

Şimdi yukarıda adresini verdiğim makalemizide referans alarak konuyu en temelden hatırlayarak ele alalım. Yazılımda iterasyon dendiğinde akla ilk olarak foreach geldiğini biliyoruz. Dolayısıyla bizler foreach döngüsü ile iterasyonel bir yapıda olan tüm referanslar üzerinde işlemler yapabilmekteyiz. Hatta kendi custom sınıflarımıza iterasyonel özellik kazandırabilmek ve foreach ile üzerinde işlem yapabilmemiz için IEnumerable interface’ini kullanmaktayız. IEnumerable’ı hatırlama mahiyetinde referans aldığımız kaynaktan ilgili yapıya dair alıntıda bulunalım;

…IEnumerable interface’i ise bir sınıfa foreach mekanizması tarafından tanınması için gerekli yetenekleri/nitelikleri kazandırır. Yani enumerator yapısını… Kaynak : C#’ta IEnumerable ve IEnumerator Interfaceleri Nedir? ve Nasıl Kullanılır?

foreach döngüsü bir referans üzerinde işlev görecekse eğer o referansın sınıfı içerisinde geriye IEnumerator döndüren ve adınında GetEnumerator olduğu bir metodun bulunmasını şart koşmaktadır. Nedir bu GetEnumerator metodu? diye sorarsanız eğer yine aşağıdaki alıntıya göz atabilirsiniz.

…GetEnumerator metodu, bir sınıfa iterasyon yapılarını kazandıracak özellikleri barındıran IEnumerator nesnesi dönen bir metotdur…Kaynak : C#’ta IEnumerable ve IEnumerator Interfaceleri Nedir? ve Nasıl Kullanılır?

Nihayetinde burada ortaya çıkan sonuç; IEnumerable interfaceinin uygulandığı sınıfa zorla GetEnumerator isimli metot implement ettirilmektedir. IEnumerator ise ilgili sınıfa iterasyon işleminde kullanılacak elemanları ve özellikleri kazandırmaktan sorumlu olacaktır.

Buraya kadar ele aldığımız tüm yapılanma kendi sınıflarımıza iterasyonel bir özellik kazandırmak için kullandığımız materyallerdir. C# 8.0, bu sınıfların asenkron karşılıkları olarak düşenebileceğimiz Asynchronous Streams başlığı altındaki IAsyncEnumerable<T> ve IAsyncEnumerator<T> alternatiflerini getirmiş bulunmaktadır.

C# 8.0’da gelen Asynchronous Streams(IAsyncEnumerable<T> ve IAsyncEnumerator<T>) yapıları sayesinde foreach döngüsü await keywordü ile asenkron işlenebilir hale gelmiştir.

Şimdi custom oluşturduğumuz bir sınıfı IAsyncEnumerable<T> interfacei ile türetelim ve ardından bir başka sınıfa IAsyncEnumerator<T> interfacei ile de gerekli iterasyonel yetenekleri kazandırarak foreach döngüsünde asenkron işlemlerimizi gerçekleştirelim.

Burada senaryo olarak elimizdeki bir sayısal listeyi temsil eden custom sınıfımızda asenkron olarak foreach döngüsünde dönmeyi inceleyelim.

İlk olarak Enumerator nesnesini oluşturalım.

    class MyEnumerator : IAsyncEnumerator<int>
    {
        List<int> numbers;
        public MyEnumerator(List<int> numbers) => this.numbers = numbers;
        int currentIndex = -1;
        public int Current => numbers[currentIndex];
        public ValueTask DisposeAsync()
        {
            Console.WriteLine("İterasyon sona erdi.");
            return new ValueTask(Task.CompletedTask);
        }
        public ValueTask<bool> MoveNextAsync()
        {
            Task.Delay(1000).Wait();
            return new ValueTask<bool>(++currentIndex < numbers.Count);
        }
    }

Ardından koleksiyonel özellik kazandıracağımız sınıfımızı oluşturalım.

    class MyList : IAsyncEnumerable<int>
    {
        List<int> numbers = new List<int>();
        public IAsyncEnumerator<int> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new MyEnumerator(numbers);
        public void Add(int number) => numbers.Add(number);
    }

Ve son olarak kullanalım;

    class Program
    {
        static void Main(string[] args)
        {
            Do().Wait();
        }

        static async Task Do()
        {
            MyList myList = new MyList();
            myList.Add(1);
            myList.Add(3);
            myList.Add(5);
            myList.Add(7);
            myList.Add(9);
            await foreach (var number in myList)
                Console.WriteLine(number);
        }
    }

Uygulamayı derleyip çalıştırdığınızda foreach döngüsünün asenkron bir şekilde ilgili koleksiyon üzerinde işlem yaptığını aşağıdaki ekran görüntüsünde olduğu gibi görebilirsiniz.
C# 8.0 - IAsyncEnumerable<T> ve IAsyncEnumerator<T> Arayüzleri İle Asenkron Iterasyonel İşlev Oluşturma

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

1 Cevap

  1. 26 Ekim 2019

    […] içeriğimizde, bir önceki IAsyncEnumerablee<T> ve IAsyncEnumeratore<T> Arayüzleri İle Asenkron Iterasyonel İşl… başlıklı makalemizle ilişkili olan Asenkron Foreach yapılanması üzerine konuşuyor […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*