Yineleyiciler (Visual Basic)
Yineleyici, listeler ve diziler gibi koleksiyonlarda adım adım ilerleyebilmek için kullanılabilir.
Yineleyici yöntemi veya get
erişimcisi bir koleksiyon üzerinde özel yineleme gerçekleştirir. Yineleyici yöntemi, her öğeyi birer birer döndürmek için Yield deyimini kullanır. Bir Yield
deyime ulaşıldığında koddaki geçerli konum hatırlanır. Yineleyici işlevi bir sonraki çağrılışında yürütme bu konumdan yeniden başlatılır.
Her İçin... kullanarak istemci kodundan bir yineleyici tüketirsiniz. Sonraki deyim veya LINQ sorgusu kullanarak.
Aşağıdaki örnekte, döngünün For Each
ilk yinelemesi, ilk Yield
deyime ulaşılana kadar yürütmenin SomeNumbers
yineleyici yönteminde ilerlemesine neden olur. Bu yineleme 3 değerini döndürür ve yineleyici yöntemindeki geçerli konum korunur. Döngünün bir sonraki yinelemesinde, yineleyici yönteminde yürütme kaldığı yerden devam eder ve bir Yield
deyime ulaştığında yeniden durduruluyor. Bu yineleme 5 değerini döndürür ve yineleyici yöntemindeki geçerli konum yeniden korunur. Yineleyici yönteminin sonuna ulaşıldığında döngü tamamlanır.
Sub Main()
For Each number As Integer In SomeNumbers()
Console.Write(number & " ")
Next
' Output: 3 5 8
Console.ReadKey()
End Sub
Private Iterator Function SomeNumbers() As System.Collections.IEnumerable
Yield 3
Yield 5
Yield 8
End Function
Yineleyici yönteminin veya get
erişimcinin dönüş türü , , IEnumerable<T>IEnumeratorveya IEnumerator<T>olabilirIEnumerable.
Yinelemeyi sonlandırmak için bir Exit Function
veya Return
deyimi kullanabilirsiniz.
Visual Basic yineleyici işlevi veya get
erişimci bildirimi bir Yineleyici değiştiricisi içerir.
Yineleyiciler Visual Studio 2012'de Visual Basic'te tanıtıldı.
Not
Basit Yineleyici örneği dışındaki makaledeki tüm örnekler için ve System.Collections.Generic
ad alanları için System.Collections
imports deyimlerini ekleyin.
Basit Yineleyici
Aşağıdaki örnekte For... içinde tek Yield
bir deyim vardır. Sonraki döngü. içinde Main
, deyim gövdesinin For Each
her yinelemesi, bir sonraki Yield
deyime devam eden yineleyici işlevine bir çağrı oluşturur.
Sub Main()
For Each number As Integer In EvenSequence(5, 18)
Console.Write(number & " ")
Next
' Output: 6 8 10 12 14 16 18
Console.ReadKey()
End Sub
Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As System.Collections.Generic.IEnumerable(Of Integer)
' Yield even numbers in the range.
For number As Integer = firstNumber To lastNumber
If number Mod 2 = 0 Then
Yield number
End If
Next
End Function
Koleksiyon Sınıfı Oluşturma
Aşağıdaki örnekte sınıfı, DaysOfTheWeek
bir GetEnumerator yöntem gerektiren arabirimini uygularIEnumerable. Derleyici, bir IEnumeratordöndüren yöntemini örtük olarak çağırırGetEnumerator
.
yöntemi deyimini GetEnumerator
kullanarak her dizeyi Yield
birer birer döndürür ve işlev bildiriminde bir Iterator
değiştirici bulunur.
Sub Main()
Dim days As New DaysOfTheWeek()
For Each day As String In days
Console.Write(day & " ")
Next
' Output: Sun Mon Tue Wed Thu Fri Sat
Console.ReadKey()
End Sub
Private Class DaysOfTheWeek
Implements IEnumerable
Public days =
New String() {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
Public Iterator Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
' Yield each day of the week.
For i As Integer = 0 To days.Length - 1
Yield days(i)
Next
End Function
End Class
Aşağıdaki örnek, bir Zoo
hayvan koleksiyonu içeren bir sınıf oluşturur.
For Each
Sınıf örneğine (theZoo
) başvuran deyimi örtük olarak yöntemini çağırırGetEnumerator
. ve özelliklerine Birds
başvuran deyimler adlandırılmış yineleyici yöntemini kullanırAnimalsForType
.Mammals
For Each
Sub Main()
Dim theZoo As New Zoo()
theZoo.AddMammal("Whale")
theZoo.AddMammal("Rhinoceros")
theZoo.AddBird("Penguin")
theZoo.AddBird("Warbler")
For Each name As String In theZoo
Console.Write(name & " ")
Next
Console.WriteLine()
' Output: Whale Rhinoceros Penguin Warbler
For Each name As String In theZoo.Birds
Console.Write(name & " ")
Next
Console.WriteLine()
' Output: Penguin Warbler
For Each name As String In theZoo.Mammals
Console.Write(name & " ")
Next
Console.WriteLine()
' Output: Whale Rhinoceros
Console.ReadKey()
End Sub
Public Class Zoo
Implements IEnumerable
' Private members.
Private animals As New List(Of Animal)
' Public methods.
Public Sub AddMammal(ByVal name As String)
animals.Add(New Animal With {.Name = name, .Type = Animal.TypeEnum.Mammal})
End Sub
Public Sub AddBird(ByVal name As String)
animals.Add(New Animal With {.Name = name, .Type = Animal.TypeEnum.Bird})
End Sub
Public Iterator Function GetEnumerator() As IEnumerator _
Implements IEnumerable.GetEnumerator
For Each theAnimal As Animal In animals
Yield theAnimal.Name
Next
End Function
' Public members.
Public ReadOnly Property Mammals As IEnumerable
Get
Return AnimalsForType(Animal.TypeEnum.Mammal)
End Get
End Property
Public ReadOnly Property Birds As IEnumerable
Get
Return AnimalsForType(Animal.TypeEnum.Bird)
End Get
End Property
' Private methods.
Private Iterator Function AnimalsForType( _
ByVal type As Animal.TypeEnum) As IEnumerable
For Each theAnimal As Animal In animals
If (theAnimal.Type = type) Then
Yield theAnimal.Name
End If
Next
End Function
' Private class.
Private Class Animal
Public Enum TypeEnum
Bird
Mammal
End Enum
Public Property Name As String
Public Property Type As TypeEnum
End Class
End Class
Deneme Blokları
Visual Basic, Try Yield
... bloğunda Try
bir deyime izin verir. Yakalamak... Finally Deyimi. Try
Deyimi olan bir Yield
bloğun blokları olabilir Catch
ve bir Finally
bloğu olabilir.
Aşağıdaki örnek, yineleyici işlevinde , Catch
ve Finally
bloklarını içerirTry
. Finally
Yineleyici işlevindeki blok, yineleme tamamlanmadan önce For Each
yürütülür.
Sub Main()
For Each number As Integer In Test()
Console.WriteLine(number)
Next
Console.WriteLine("For Each is done.")
' Output:
' 3
' 4
' Something happened. Yields are done.
' Finally is called.
' For Each is done.
Console.ReadKey()
End Sub
Private Iterator Function Test() As IEnumerable(Of Integer)
Try
Yield 3
Yield 4
Throw New Exception("Something happened. Yields are done.")
Yield 5
Yield 6
Catch ex As Exception
Console.WriteLine(ex.Message)
Finally
Console.WriteLine("Finally is called.")
End Try
End Function
Deyimi Yield
bir Catch
blok veya Finally
blok içinde olamaz.
For Each
Gövde (yineleyici yöntemi yerine) bir özel durum oluşturursa, yineleyici işlevindeki bir Catch
blok yürütülür, ancak yineleyici işlevindeki bir Finally
blok yürütülür. Catch
Yineleyici işlevinin içindeki bir blok yalnızca yineleyici işlevinin içinde oluşan özel durumları yakalar.
Anonim Yöntemler
Visual Basic'te anonim bir işlev yineleyici işlevi olabilir. Aşağıdaki örnek bunu göstermektedir.
Dim iterateSequence = Iterator Function() _
As IEnumerable(Of Integer)
Yield 1
Yield 2
End Function
For Each number As Integer In iterateSequence()
Console.Write(number & " ")
Next
' Output: 1 2
Console.ReadKey()
Aşağıdaki örnekte bağımsız değişkenleri doğrulayan yineleyici olmayan bir yöntem vardır. yöntemi, koleksiyon öğelerini açıklayan anonim bir yineleyicinin sonucunu döndürür.
Sub Main()
For Each number As Integer In GetSequence(5, 10)
Console.Write(number & " ")
Next
' Output: 5 6 7 8 9 10
Console.ReadKey()
End Sub
Public Function GetSequence(ByVal low As Integer, ByVal high As Integer) _
As IEnumerable
' Validate the arguments.
If low < 1 Then
Throw New ArgumentException("low is too low")
End If
If high > 140 Then
Throw New ArgumentException("high is too high")
End If
' Return an anonymous iterator function.
Dim iterateSequence = Iterator Function() As IEnumerable
For index = low To high
Yield index
Next
End Function
Return iterateSequence()
End Function
Yineleyici işlevinin içinde doğrulama varsa, gövdenin ilk yinelemesi For Each
başlayana kadar doğrulama gerçekleştirilemez.
Yineleyicileri Genel Listeyle Kullanma
Aşağıdaki örnekte, Stack(Of T)
genel sınıf genel arabirimini uygular IEnumerable<T> . Push
yöntemi, türündeki T
bir diziye değerler atar. yöntemi, GetEnumerator deyimini kullanarak Yield
dizi değerlerini döndürür.
Genel yönteme ek olarak, genel GetEnumeratorGetEnumerator olmayan yöntem de uygulanmalıdır. Bunun nedeni, öğesinden IEnumerabledevralınıyor olmasıdırIEnumerable<T>. Genel olmayan uygulama, genel uygulamaya saptır.
Örnek, aynı veri koleksiyonu aracılığıyla yinelemenin çeşitli yollarını desteklemek için adlandırılmış yineleyiciler kullanır. Bu adlandırılmış yineleyiciler, ve BottomToTop
özellikleri ve yöntemidir.TopToBottom
TopN
Özellik BottomToTop
bildirimi anahtar sözcüğünü Iterator
içerir.
Sub Main()
Dim theStack As New Stack(Of Integer)
' Add items to the stack.
For number As Integer = 0 To 9
theStack.Push(number)
Next
' Retrieve items from the stack.
' For Each is allowed because theStack implements
' IEnumerable(Of Integer).
For Each number As Integer In theStack
Console.Write("{0} ", number)
Next
Console.WriteLine()
' Output: 9 8 7 6 5 4 3 2 1 0
' For Each is allowed, because theStack.TopToBottom
' returns IEnumerable(Of Integer).
For Each number As Integer In theStack.TopToBottom
Console.Write("{0} ", number)
Next
Console.WriteLine()
' Output: 9 8 7 6 5 4 3 2 1 0
For Each number As Integer In theStack.BottomToTop
Console.Write("{0} ", number)
Next
Console.WriteLine()
' Output: 0 1 2 3 4 5 6 7 8 9
For Each number As Integer In theStack.TopN(7)
Console.Write("{0} ", number)
Next
Console.WriteLine()
' Output: 9 8 7 6 5 4 3
Console.ReadKey()
End Sub
Public Class Stack(Of T)
Implements IEnumerable(Of T)
Private values As T() = New T(99) {}
Private top As Integer = 0
Public Sub Push(ByVal t As T)
values(top) = t
top = top + 1
End Sub
Public Function Pop() As T
top = top - 1
Return values(top)
End Function
' This function implements the GetEnumerator method. It allows
' an instance of the class to be used in a For Each statement.
Public Iterator Function GetEnumerator() As IEnumerator(Of T) _
Implements IEnumerable(Of T).GetEnumerator
For index As Integer = top - 1 To 0 Step -1
Yield values(index)
Next
End Function
Public Iterator Function GetEnumerator1() As IEnumerator _
Implements IEnumerable.GetEnumerator
Yield GetEnumerator()
End Function
Public ReadOnly Property TopToBottom() As IEnumerable(Of T)
Get
Return Me
End Get
End Property
Public ReadOnly Iterator Property BottomToTop As IEnumerable(Of T)
Get
For index As Integer = 0 To top - 1
Yield values(index)
Next
End Get
End Property
Public Iterator Function TopN(ByVal itemsFromTop As Integer) _
As IEnumerable(Of T)
' Return less than itemsFromTop if necessary.
Dim startIndex As Integer =
If(itemsFromTop >= top, 0, top - itemsFromTop)
For index As Integer = top - 1 To startIndex Step -1
Yield values(index)
Next
End Function
End Class
Söz Dizimi Bilgileri
Yineleyici bir yöntem veya get
erişimci olarak oluşabilir. Yineleyici bir olayda, örnek oluşturucusunda, statik oluşturucuda veya statik yıkıcıda gerçekleşemez.
Deyimdeki Yield
ifade türünden yineleyicinin dönüş türüne örtük dönüştürme bulunmalıdır.
Visual Basic'te bir yineleyici yönteminde parametre ByRef
olamaz.
Visual Basic'te "Yield" ayrılmış bir sözcük değildir ve yalnızca bir yöntemde veya get
erişimcide kullanıldığında özel bir Iterator
anlamı vardır.
Teknik Uygulama
Bir yineleyiciyi bir yöntem olarak yazmanıza rağmen, derleyici bunu iç içe geçmiş bir sınıfa (aslında bir durum makinesi) çevirir. Bu sınıf, istemci kodundaki döngü devam ettikçe yineleyicinin For Each...Next
konumunu izler.
Derleyicinin ne yaptığını görmek için Ildasm.exe aracını kullanarak yineleyici yöntemi için oluşturulan ortak ara dil kodunu görüntüleyebilirsiniz.
Bir sınıf veya yapı için yineleyici oluşturduğunuzda arabirimin tamamını IEnumerator uygulamanız gerekmez. Derleyici yineleyiciyi algıladığında, veya IEnumerator<T> arabiriminin Current
, MoveNext
ve Dispose
yöntemlerini IEnumerator otomatik olarak oluşturur.
Döngünün For Each…Next
her ardışık yinelemesinde (veya doğrudan çağrısında IEnumerator.MoveNext
), sonraki yineleyici kod gövdesi önceki Yield
deyimden sonra devam eder. Daha sonra yineleyici gövdesinin Yield
sonuna ulaşılana kadar veya bir veya Return
deyimiyle karşılaşılana kadar sonraki Exit Function
deyime devam eder.
Yineleyiciler yöntemini desteklemez IEnumerator.Reset . Baştan yeniden yinelemek için yeni bir yineleyici edinmeniz gerekir.
Ek bilgi için bkz . Visual Basic Dil Belirtimi.
Yineleyicilerin Kullanımı
Yineleyiciler, bir liste dizisini doldurmak için karmaşık kod kullanmanız gerektiğinde döngünün For Each
basitliğini korumanızı sağlar. Bu, aşağıdakileri yapmak istediğinizde yararlı olabilir:
İlk
For Each
döngü yinelemesinin ardından liste dizisini değiştirin.Döngünün ilk yinelenmesinden önce büyük bir listeyi tam olarak
For Each
yüklemekten kaçının. Tablo satırlarından oluşan bir toplu iş yüklemek için sayfalanmış getirme işlemi örnek olarak verilmiştir. Başka bir örnek, .NET Framework içinde yineleyiciler uygulayan yöntemidir EnumerateFiles .Listeyi yineleyicide derlemeyi kapsülleyin. Yineleyici yönteminde, listeyi derleyebilir ve ardından her sonucu bir döngü halinde vekleyebilirsiniz.