ProgrammazioneSviluppatore di librerie .NET / Middle VB.NET Developer

Descrivi i metodi di implementazione e utilizzo degli iteratori (termine Enumerable / Iterator) in Visual Basic, e come creare collezioni iterabili personalizzate.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della domanda
Gli iteratori sono diventati parte integrante dei linguaggi di programmazione con l'emergere delle collezioni che devono essere iterate. In Visual Basic, a partire dalla versione .NET, è stato introdotto il supporto per IEnumerable/IEnumerator, che consente di implementare collezioni iterabili personalizzate e utilizzare il ciclo For Each per accedere in modo conveniente e conciso al contenuto delle collezioni.

Problema
Molti sviluppatori si limitano ad utilizzare solo le collezioni predefinite, oppure non implementano correttamente l'interfaccia IEnumerable, rendendo impossibile l'iterazione degli oggetti tramite For Each. Inoltre, la realizzazione e la gestione dello stato dell'iteratore tramite Current e MoveNext può risultare complessa.

Soluzione
Per supportare le iterazioni, il tipo implementa l'interfaccia IEnumerable (o IEnumerable(Of T) generico). Implementa la funzione GetEnumerator che restituisce un oggetto che implementa IEnumerator. In VB.NET è anche possibile utilizzare i metodi iteratori con la parola chiave Yield (a partire da VB 2015), il che semplifica notevolmente l'implementazione dell'iterazione.

Esempio di codice:

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 ' per VB 2015+ Next End Function End Class ' Utilizzo: For Each n As Integer In New SimpleCollection() Console.WriteLine(n) Next

Caratteristiche principali:

  • Per supportare For Each, il tipo deve implementare IEnumerable / IEnumerable(Of T).
  • L'implementazione è solitamente delegata a una collezione esistente o viene creata una propria.
  • Con Yield è possibile creare iteratori in modo semplice; senza Yield, sarà necessario implementare manualmente IEnumerator.

Domande insidiose.

È obbligatorio implementare entrambe le interfacce: IEnumerable e IEnumerator, per supportare For Each?

No, è sufficiente implementare IEnumerable e restituire un iteratore compatibile. Se vuoi implementare l'iterazione, puoi utilizzare l'IEnumerator già esistente di una collezione annidata. Ma per una personalizzazione completa è necessaria l'implementazione di entrambe le parti.

Esempio di codice:

Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator Return arr.GetEnumerator() ' utilizziamo l'iteratore predefinito dell'array End Function

È possibile implementare IEnumerable solo esplicitamente (Explicit Interface Implementation) in Visual Basic?

Sì, è possibile implementare l'interfaccia in modo esplicito, soprattutto quando la tua collezione ha già il proprio GetEnumerator e desideri nascondere l'implementazione dell'interfaccia. Non sarà possibile chiamare direttamente tale GetEnumerator, ma For Each funzionerà.

Esempio di codice:

Public Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator ' ...corpo del metodo End Function

Cosa succede se GetEnumerator restituisce Nothing?

Verrà sollevata un'eccezione al primo tentativo di iterare sulla collezione, poiché For Each si aspetta un iteratore valido.

Errori comuni e anti-pattern

  • Implementazione errata dei metodi MoveNext/Current, portando a elementi saltati o errori.
  • Violazione dello stato dell'iteratore tra le chiamate (ad esempio, l'indice non viene reimpostato durante l'iterazione successiva).
  • Eccezione StopIteration assente o non corretta.

Esempio dalla vita reale

Caso negativo

La classe della collezione non ha implementato IEnumerable, mentre un metodo separato Next è stato creato per iterare gli elementi. Di conseguenza, non può essere utilizzato in metodi universali o For Each, portando alla necessità di scrivere metodi aggiuntivi.

Pro:

  • Implementazione rapida secondo necessità.

Contro:

  • Non è possibile utilizzare For Each e LINQ.
  • Perdita di compatibilità con .NET API.

Caso positivo

Lo sviluppatore ha implementato IEnumerable e GetEnumerator, la collezione ora funziona con For Each e si integra con LINQ.

Pro:

  • Super compatibilità con l'infrastruttura .NET.
  • Versatilità e semplicità d'uso.

Contro:

  • Richiede un po' più di codice per una implementazione manuale prima dell'arrivo di Yield.