Dieser Artikel wurde manuell übersetzt. Bewegen Sie den Mauszeiger über die Sätze im Artikel, um den Originaltext anzuzeigen. Weitere Informationen
Übersetzung
Original
Informationen
Das angeforderte Thema wird unten angezeigt. Es ist jedoch nicht in dieser Bibliothek vorhanden.

Iteratoren (C# und Visual Basic)

Ein Iterator kann verwendet werden, um Auflistungen wie Listen und Arrays zu durchlaufen.

Eine Iteratormethode oder ein get Accessor führt eine benutzerdefinierte Iteration über einer Auflistung aus. Eine Iteratormethode verwendet die - Anweisung Yield (Visual Basic) oder Rendite (C#), um jedes Element einzeln zurückzugeben. Wenn eine Yield oder yield return-Anweisung erreicht ist, wird an die aktuelle Position im Code gespeichert. Die Ausführung von diesem Speicherort neu gestartet, beim nächsten Öffnen der Iteratorfunktion aufgerufen wird.

Sie verwenden einen Iterator vom Clientcode, indem Sie eine - Anweisung Für jedes... Next-Schleife (Visual Basic) oder foreach (C#) oder indem Sie eine LINQ-Abfrage verwenden.

Im folgenden Beispiel läßt die erste Iteration der For Each oder foreach Schleife die Ausführung in der SomeNumbers Iteratormethode weiterlaufen bis dort die erste Yield oder yield return Anweisung erreicht wird. Diese Iteration gibt den Wert 3 zurück, und die aktuelle Position in der Iteratormethode wird beibehalten. Klicken Sie auf der nächsten Iteration der Schleife, wird die Ausführung in der Iteratormethode von fort, wo diese durch unterzogen und daraufhin erneut, wenn sie eine Yield oder yield return-Anweisung erreicht. Diese Iteration gibt den Wert 5 zurück, und die aktuelle Position in der Iteratormethode wird erneut beibehalten. Die Schleife wird beendet, wenn das Ende der Iteratormethode erreicht wird.


static void Main()
{
    foreach (int number in SomeNumbers())
    {
        Console.Write(number.ToString() + " ");
    }
    // Output: 3 5 8
    Console.ReadKey();
}

public static System.Collections.IEnumerable SomeNumbers()
{
    yield return 3;
    yield return 5;
    yield return 8;
}


Der Rückgabetyp einer Iteratormethode oder des get Accessor kann IEnumerable, IEnumerable<T>, IEnumerator oder IEnumerator<T> sein.

Sie können eine Exit Function oder Return-Anweisung (Visual Basic) oder yield break-Anweisung (C#) die Iteration zu beenden.

Eine Visual Basic Iteratorfunktion oder eine get Accessordeklaration umfasst einen Iterator-Modifizierer.

Iteratoren wurden in C# mit Visual Studio 2005 und in Visual Basic mit Visual Studio 2012 eingeführt.

In diesem Thema

Das folgende Beispiel zeigt eine einzelne Yield oder yield return Anweisung, die sich innerhalb einer Für... Next-Schleife (Visual Basic) oder für (C#) Schleife befindet. In Main führt jede Iteration des For Each oder foreach-Anweisungstexts zu einem Aufruf der Iteratorfunktion, die zur jeweils nächsten Yield oder yield return Anweisung weiterleitet.


static void Main()
{
    foreach (int number in EvenSequence(5, 18))
    {
        Console.Write(number.ToString() + " ");
    }
    // Output: 6 8 10 12 14 16 18
    Console.ReadKey();
}

public static System.Collections.Generic.IEnumerable<int>
    EvenSequence(int firstNumber, int lastNumber)
{
    // Yield even numbers in the range.
    for (int number = firstNumber; number <= lastNumber; number++)
    {
        if (number % 2 == 0)
        {
            yield return number;
        }
    }
}


Hinweis Hinweis

Für die verbleibenden Beispiele im Thema schließen Sie Imports-Anweisungen (Visual Basic) oder using-Direktiven (C#) für die System.Collections- und System.Collections.Generic-Namespaces ein.

Im folgenden Beispiel DaysOfTheWeek implementiert die Klasse die IEnumerable-Schnittstelle, die eine GetEnumerator-Methode erfordert. Der Compiler ruft implizit die GetEnumerator-Methode, die IEnumerator zurückgibt.

Die GetEnumerator-Methode gibt jede Zeichenfolge einzeln zurück, indem sie die Yield oder yield return-Anweisung verwendet. Im Visual Basic Code ist ein Iterator-Modifizierer in der Funktionsdeklaration.


static void Main()
{
    DaysOfTheWeek days = new DaysOfTheWeek();

    foreach (string day in days)
    {
        Console.Write(day + " ");
    }
    // Output: Sun Mon Tue Wed Thu Fri Sat
    Console.ReadKey();
}

public class DaysOfTheWeek : IEnumerable
{
    private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

    public IEnumerator GetEnumerator()
    {
        for (int index = 0; index < days.Length; index++)
        {
            // Yield each day of the week.
            yield return days[index];
        }
    }
}


Das folgende Beispiel erzeugt eine Zoo-Klasse, die eine Auflistung von Tieren enthält.

Die For Each oder foreach-Anweisung, die die Klasseninstanz (theZoo) implizit verweist, GetEnumerator ruft die Methode auf. Die For Each oder foreach-Anweisungen, die die Birds und Mammals-Eigenschaften verweisen, verwenden AnimalsForType, das Iteratormethode genannt wird.


static void Main()
{
    Zoo theZoo = new Zoo();

    theZoo.AddMammal("Whale");
    theZoo.AddMammal("Rhinoceros");
    theZoo.AddBird("Penguin");
    theZoo.AddBird("Warbler");

    foreach (string name in theZoo)
    {
        Console.Write(name + " ");
    }
    Console.WriteLine();
    // Output: Whale Rhinoceros Penguin Warbler

    foreach (string name in theZoo.Birds)
    {
        Console.Write(name + " ");
    }
    Console.WriteLine();
    // Output: Penguin Warbler

    foreach (string name in theZoo.Mammals)
    {
        Console.Write(name + " ");
    }
    Console.WriteLine();
    // Output: Whale Rhinoceros

    Console.ReadKey();
}

public class Zoo : IEnumerable
{
    // Private members.
    private List<Animal> animals = new List<Animal>();

    // Public methods.
    public void AddMammal(string name)
    {
        animals.Add(new Animal { Name = name, Type = Animal.TypeEnum.Mammal });
    }

    public void AddBird(string name)
    {
        animals.Add(new Animal { Name = name, Type = Animal.TypeEnum.Bird });
    }

    public IEnumerator GetEnumerator()
    {
        foreach (Animal theAnimal in animals)
        {
            yield return theAnimal.Name;
        }
    }

    // Public members.
    public IEnumerable Mammals
    {
        get { return AnimalsForType(Animal.TypeEnum.Mammal); }
    }

    public IEnumerable Birds
    {
        get { return AnimalsForType(Animal.TypeEnum.Bird); }
    }

    // Private methods.
    private IEnumerable AnimalsForType(Animal.TypeEnum type)
    {
        foreach (Animal theAnimal in animals)
        {
            if (theAnimal.Type == type)
            {
                yield return theAnimal.Name;
            }
        }
    }

    // Private class.
    private class Animal
    {
        public enum TypeEnum { Bird, Mammal }

        public string Name { get; set; }
        public TypeEnum Type { get; set; }
    }
}


Visual Basic ermöglicht eine Yield-Anweisung im Try-Block von Try...Catch...Finally-Anweisung (Visual Basic). Ein Try-Block, der eine Yield-Anweisung hat, kann Catch Blöcke haben und kann einen Finally-Block haben.

C#-Hinweis C#-Hinweis:

C# ermöglicht eine yield return-Anweisung im try-Block einer try-finally-Anweisung-Anweisung. Ein try-Block, der eine yield return-Anweisung hat, kann keine catch Blöcke haben.

Im folgenden Beispiel Visual Basic umfasst Try, Catch, und Finally Blöcke in einem Iterator arbeiten. Der Finally-Block in der Iteratorfunktion führt vor der For Each Iterationsende aus.


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


Eine Yield-Anweisung kann nicht innerhalb eines Catch-Blocks oder eines - Blocks Finally sein.

Wenn der For Each Text (anstelle der Iteratormethode) eine Ausnahme auslöst, wird ein Catch-Block in der Iteratorfunktion nicht ausgeführt, aber ein Finally-Block in der Iteratorfunktion wird ausgeführt. Ein Catch-Block in einer Iteratorfunktion fängt nur Ausnahmen ab, die in der Iteratorfunktion auftreten.

In Visual Basic (jedoch nicht in C#), können anonyme Funktion eine Iteratorfunktion sein. Dies wird anhand des folgenden Beispiels veranschaulicht:


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()


Im folgenden Beispiel Visual Basic verfügt über eine NichtIteratormethode, die die Argumente überprüft. Die - Methode gibt das Ergebnis eines anonymen Iterators zurück, der die Auflistungselemente beschreibt.


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


Wenn die Validierung stattdessen in der Iteratorfunktion ist, kann die Validierung nicht bis zum Anfang der ersten Iteration des For Each Text ausgeführt werden.

Im folgenden Beispiel implementiert die generische Klasse Stack(Of T) die generische - Schnittstelle IEnumerable<T>. Die Push-Methode weist einem Array vom Typ T Werte zu. Die - Methode gibt die GetEnumerator Arraywerte zurück, indem sie die Yield oder yield return-Anweisung verwendet.

Neben der generischen Methode GetEnumerator muss die nicht generische GetEnumerator-Methode auch implementiert werden. Dies ist, da IEnumerable<T> von IEnumerable erbt. Die nicht generische Implementierung beugt sich der generischen Implementierung.

Das Beispiel verwendet benannte Iteratoren, um verschiedene Wege der Iteration durch dieselbe Datenauflistung zu unterstützen. Diese benannten Iteratoren sind die TopToBottom und BottomToTop-Eigenschaften und die TopN-Methode.

Die BottomToTop-Eigenschaft verwendet einen Iterator in einem get Accessor. Im Visual Basic Code umfasst die Eigenschaftendeklaration das Iterator-Schlüsselwort.


static void Main()
{
    Stack<int> theStack = new Stack<int>();

    //  Add items to the stack.
    for (int number = 0; number <= 9; number++)
    {
        theStack.Push(number);
    }

    // Retrieve items from the stack.
    // foreach is allowed because theStack implements
    // IEnumerable<int>.
    foreach (int number in theStack)
    {
        Console.Write("{0} ", number);
    }
    Console.WriteLine();
    // Output: 9 8 7 6 5 4 3 2 1 0

    // foreach is allowed, because theStack.TopToBottom
    // returns IEnumerable(Of Integer).
    foreach (int number in theStack.TopToBottom)
    {
        Console.Write("{0} ", number);
    }
    Console.WriteLine();
    // Output: 9 8 7 6 5 4 3 2 1 0

    foreach (int number in theStack.BottomToTop)
    {
        Console.Write("{0} ", number);
    }
    Console.WriteLine();
    // Output: 0 1 2 3 4 5 6 7 8 9

    foreach (int number in theStack.TopN(7))
    {
        Console.Write("{0} ", number);
    }
    Console.WriteLine();
    // Output: 9 8 7 6 5 4 3

    Console.ReadKey();
}

public class Stack<T> : IEnumerable<T>
{
    private T[] values = new T[100];
    private int top = 0;

    public void Push(T t)
    {
        values[top] = t;
        top++;
    }
    public T Pop()
    {
        top--;
        return values[top];
    }

    // This method implements the GetEnumerator method. It allows
    // an instance of the class to be used in a foreach statement.
    public IEnumerator<T> GetEnumerator()
    {
        for (int index = top - 1; index >= 0; index--)
        {
            yield return values[index];
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerable<T> TopToBottom
    {
        get { return this; }
    }

    public IEnumerable<T> BottomToTop
    {
        get
        {
            for (int index = 0; index <= top - 1; index++)
            {
                yield return values[index];
            }
        }
    }

    public IEnumerable<T> TopN(int itemsFromTop)
    {
        // Return less than itemsFromTop if necessary.
        int startIndex = itemsFromTop >= top ? 0 : top - itemsFromTop;

        for (int index = top - 1; index >= startIndex; index--)
        {
            yield return values[index];
        }
    }

}


Ein Iterator kann als Methode oder Accessor get auftreten. Ein Iterator kann nicht in einem Ereignis, in einem Instanzenkonstruktor, in einem statischen Konstruktor oder in einem statischen Destruktor auftreten.

Eine implizite Konvertierung muss vom Ausdruck sind in der - Anweisung Yield (Visual Basic) oder yield return (C#) in den Rückgabetyp des Iterators.

In Visual Basic kann eine Iteratormethode keine ByRef-Parameter haben. In C# kann eine Iteratormethode keine ref oder out-Parameter haben.

In Visual Basic"Yield" ist kein reserviertes Wort und ist eine besondere Bedeutung, falls dies in einer Iterator-Methode oder einem get Accessor verwendet wird. In C# "Yield" ist kein reserviertes Wort und ist eine besondere Bedeutung, falls dies vor einem return oder break-Schlüsselwort verwendet wird.

Obwohl ein Iterator als Methode geschrieben wird, wird sie vom Compiler in eine geschachtelte Klasse übersetzt, die tatsächlich einem Zustandsautomaten entspricht. Diese Klasse registriert die Position des Iterators, solange die For Each...Next- oder foreach-Schleife im Clientcode fortgesetzt wird.

Um zu sehen, was der Compiler tut, können Sie das Ildasm.exe Tool verwenden, um sich den Microsoft Intermediate Language-Code anzeigen zu lassen, der für eine Iteratormethode generiert wird.

Wenn Sie einen Iterator für - Klasse oder Struktur erstellen, müssen Sie die gesamte IEnumerator-Schnittstelle nicht implementieren. Wenn der Compiler den Iterator erkennt, generiert er automatisch Current, MoveNext und Dispose-Methoden der IEnumerator oder IEnumerator<T>-Schnittstelle.

Klicken Sie in aufeinander folgenden Iterationen der Schleife For Each…Next oder foreach (oder des direkten Aufruf zum IEnumerator.MoveNext), den folgenden Iteratorcodetextzusammenfassungen nach vorherigen Yield oder der yield return-Anweisung. Er fährt dann zu folgenden Yield oder zur yield return-Anweisung fortgesetzt, bis das Ende des Iteratortexts erreicht ist, oder bis eine Exit Function oder Return-Anweisung (Visual Basic) oder yield break-Anweisung (C#) auftritt.

Iteratoren unterstützen die IEnumerator.Reset-Methode nicht. Um von Anfang an zu überprüfen, müssen Sie sich ein neuer Iterator.

Weitere Informationen finden Sie unter Visual Basic-Sprachspezifikation oder C#-Sprachspezifikation.

Iteratoren ermöglichen Ihnen, die Einfachheit einer For Each-Schleife beibehalten, wenn Sie komplexen Code verwenden müssen, um eine Listensequenz aufzufüllen. Dies kann hilfreich sein, wenn Sie Folgendes durchführen möchten:

  • Ändern Sie die Listensequenz nach der ersten Schleifeniteration For Each.

  • Vermeiden Sie es, noch vor der ersten Iteration einer For Each Schleife eine große Liste vollständig zu laden . Ein Beispiel hierfür ist ein ausgelagerter Abruf, um einen Satz Tabellenzeilen zu laden. Ein weiteres Beispiel ist die Methode, die EnumerateFiles Iteratoren innerhalb von .NET Framework implementiert.

  • Kapseln Sie das Erstellen der Liste im Iterator. In der Iteratormethode können Sie die Liste erstellen und jedes Ergebnis in einer Schleife dann führen.

Die folgenden C#-Blogs enthalten weitere Informationen über die Verwendung von Iteratoren.

Fanden Sie dies hilfreich?
(1500 verbleibende Zeichen)
Vielen Dank für Ihr Feedback.

Community-Beiträge

Anzeigen:
© 2015 Microsoft