Soru Tarihçesi
Iteratörler, üzerinde geçiş yapılması gereken koleksiyonların ortaya çıkmasıyla birlikte programlama dillerinin önemli bir parçası haline geldi. Visual Basic'te .NET sürümünden itibaren IEnumerable/IEnumerator desteği ile özel yinelemeli koleksiyonlar oluşturmak ve koleksiyonların içeriğine kolay ve özlü bir şekilde erişmek için For Each döngüsü kullanılabilir.
Sorun
Birçok geliştirici yalnızca yerleşik koleksiyonları kullanmakla sınırlı kalmakta ya da IEnumerable arayüzünü doğru bir şekilde uygulamadıkları için For Each üzerinden nesneleri geçiş yapmak mümkün olmamaktadır. Ayrıca, Current ve MoveNext üzerinden iteratörün durumunu yönetmek zorlayıcı olmaktadır.
Çözüm
Yinelemeleri desteklemek için tür, IEnumerable (veya genel IEnumerable(Of T)) arayüzünü uygulamalıdır. IEnumerator'ı uygulayan bir nesne döndüren GetEnumerator fonksiyonunu oluşturun. VB.NET'te, yinelemeli yöntemler için Yield anahtar kelimesi (VB 2015'ten itibaren) de kullanılabilir, bu da geçişin uygulanmasını büyük ölçüde basitleştirir.
Kod örneği:
Imports System.Collections Public Class SimpleCollection Implements IEnumerable Private arr() As Integer = {1, 2, 3} Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator For Each i In arr Yield i ' VB 2015+ için Next End Function End Class ' Kullanım: For Each n As Integer In New SimpleCollection() Console.WriteLine(n) Next
Anahtar özellikler:
For Each desteği için hem IEnumerable hem de IEnumerator arayüzlerini uygulamak zorunlu mu?
Hayır, yeterli olan sadece IEnumerable'ı uygulamak ve uyumlu bir iteratör döndürmektir. Geçiş yapmak istiyorsanız, gömülü koleksiyonun mevcut IEnumerator'ını kullanabilirsiniz. Ancak tam özelleştirme için her iki parçanın da uygulanması gerekir.
Kod örneği:
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return arr.GetEnumerator() ' dizinin gömülü iteratörünü kullanıyoruz End Function
Visual Basic’de IEnumerable'ı yalnızca açık bir şekilde (Explicit Interface Implementation) uygulamak mümkün mü?
Evet, arayüzü açıkça uygulamak mümkündür, özellikle de koleksiyonunuzun kendi GetEnumerator'ı varsa ve arayüzün uygulanmasını gizlemek istiyorsanız. Böyle bir GetEnumerator'ı doğrudan çağırmak mümkün olmaz, ancak For Each çalışacaktır.
Kod örneği:
Public Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator ' ...metodun gövdesi End Function
GetEnumerator Nothing dönerse ne olur?
Koleksiyonu ilk geçiş yapma girişiminde bir istisna atılır, çünkü For Each uyumlu bir iteratör bekler.
Koleksiyon sınıfı IEnumerable'ı uygulamadı ve elemanları geçiş yapmak için ayrı bir Next metodu oluşturdu. Sonuç olarak, genel yöntemlerde veya For Each içinde kullanılamaz, ek metodlar yazmak zorunda kaldık.
Artılar:
Eksikler:
Geliştirici IEnumerable ve GetEnumerator'ı uyguladı, koleksiyon artık For Each ile çalışıyor ve LINQ ile bütünleşiyor.
Artılar:
Eksikler: