programowanieProgramista VB.NET

Opisz, jak działa pętla For...Each...Next w Visual Basic z niestandardowymi kolekcjami. Jak stworzyć własną kolekcję do iteracji w For Each i co należy wdrożyć?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania:

Operator For Each...Next w Visual Basic umożliwia iterację przez elementy kolekcji lub tablic. Od VB6 wspierano iterację po standardowych kolekcjach, a w VB.NET — po wszystkich typach implementujących określony interfejs. Jednak gdy zachodzi potrzeba tworzenia niestandardowych kolekcji do własnej iteracji, ważne jest poprawne wdrożenie odpowiedniej infrastruktury.

Problem

Nie wystarczy wdrożyć przechowywania elementów — operatory For Each wymagają wsparcia specjalizowanego interfejsu IEnumerable. Często budowy niestandardowych kolekcji ograniczały się do metody Add/Get, obiekt przemieniał się w "czarną skrzynkę" do iteracji. To utrudniało integrację z językową strukturą iteracji i prowadziło do błędów.

Rozwiązanie

Aby For Each poprawnie działał z twoją kolekcją, należy wdrożyć interfejs IEnumerable, a dla wsparcia pracy z typowanymi elementami — IEnumerable(Of T). Należy także stworzyć własny enumerator (Enumerator), implementujący interfejs IEnumerator (lub IEnumerator(Of T) w wersjach ogólnych).

Przykład:

Public Class IntCollection Implements IEnumerable(Of Integer) Private ReadOnly items As New List(Of Integer)() Public Sub Add(value As Integer) items.Add(value) End Sub Public Function GetEnumerator() As IEnumerator(Of Integer) _ Implements IEnumerable(Of Integer).GetEnumerator Return items.GetEnumerator() End Function Private Function IEnumerable_GetEnumerator() As IEnumerator _ Implements IEnumerable.GetEnumerator Return GetEnumerator() End Function End Class ' Użycie: Dim col As New IntCollection() col.Add(10) col.Add(20) col.Add(30) For Each n As Integer In col Console.WriteLine(n) Next

Kluczowe cechy:

  • Wymagana jest implementacja metod GetEnumerator oraz zwracanie IEnumerator lub IEnumerator(Of T).
  • Wsparcie dla generic- oraz non-generic IEnumerable dla kompatybilności z różnymi wersjami środowiska.
  • Gotowa kolekcja może uczestniczyć w LINQ, For Each oraz współpracować ze standardową infrastrukturą .NET.

Pytania z pułapką.

Czy można zaimplementować For Each bez interfejsu IEnumerable, po prostu pisząc metodę GetEnumerator?

Nie, Visual Basic wymaga oficjalnego wsparcia interfejsu IEnumerable/IEnumerable(Of T), aby kompilator rozpoznał kolekcję jako kompatybilną z For Each.

Czy enumerator musi być oddzielną klasą?

Nie, jeśli baza danych elementów wspiera standardowy enumerator (na przykład, jeśli agregujesz List(Of T)), można zwracać jego GetEnumerator. Tylko w trudnych scenariuszach może być potrzebna własna klasa implementująca IEnumerator.

Czy można modyfikować kolekcję wewnątrz pętli For Each?

Nie, zmiana kolekcji podczas iteracji spowoduje InvalidOperationException. Dla poprawnego przetwarzania potrzebne są specjalne strategie (na przykład kopiowanie listy przed iteracją lub użycie indeksowania).

Typowe błędy i antywzorce

  • Implementacja tylko Add/Remove bez IEnumerable — nie można używać For Each.
  • Zwracanie nieistniejących lub nieprawidłowych enumeratorów — prowadzi do awarii podczas iteracji.
  • Zmiana kolekcji w ciele pętli For Each.

Przykład z życia

Negatywny przypadek

W firmie zaprojektowano własną klasę MyCollection z dodawaniem i usuwaniem przez tablicę, ale bez implementacji interfejsu IEnumerable. For Each nie działał, trzeba było używać zwykłych pętli i publicznego pola z elementami.

Zalety:

  • Szybkie tworzenie kolekcji — minimalna ilość kodu.

Wady:

  • Nie można było używać For Each, LINQ, nie można było pracować z nimi jak ze standardowymi kolekcjami.
  • Pojawił się zdublowany kod iteracji w różnych miejscach.

Pozytywny przypadek

Klasę przerobiono, implementując IEnumerable(Of T). Po tym kolekcja łatwo i standardowo była wykorzystywana w For Each, a także stała się kompatybilna z LINQ.

Zalety:

  • Czysta, standardowa składnia.
  • Iteracja przez kolekcję jest kompatybilna ze wszystkimi możliwościami infrastrukturalnymi VB.NET.

Wady:

  • Wymaga dodania większej ilości kodu dla wsparcia interfejsów.