Histoire de la question :
L'instruction For Each...Next en Visual Basic permet de parcourir les éléments des collections ou des tableaux. À partir de VB6, le parcours des collections standard était supporté, et dans VB.NET, pour tous les types qui implémentent une interface spécifique. Mais quand il s'agit de créer des collections utilisateurs pour un parcours personnalisé, il est important d'implémenter correctement l'infrastructure requise.
Problème
Il ne suffit pas d'implémenter le stockage des éléments — les instructions For Each nécessitent le soutien d'une interface spécialisée IEnumerable. Souvent, la création de collections personnalisées se limitait aux méthodes Add/Get, l'objet devenant une "boîte noire" pour l'itération. Cela empêchait l'intégration avec la structure de parcours du langage et entraînait des erreurs.
Solution
Pour que For Each fonctionne correctement avec votre collection, il est nécessaire d'implémenter l'interface IEnumerable, et pour prendre en charge le travail avec des éléments typés — IEnumerable(Of T). Il faut également créer un énumérateur (Enumerator) personnalisé qui implémente l'interface IEnumerator (ou IEnumerator(Of T) dans les versions génériques).
Exemple:
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 ' Utilisation : 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
Caractéristiques clés :
Peut-on implémenter For Each sans l'interface IEnumerable, simplement en écrivant une méthode GetEnumerator ?
Non, Visual Basic nécessite le soutien officiel de l'interface IEnumerable/IEnumerable(Of T) pour que le compilateur reconnaisse la collection comme compatible avec For Each.
L'énumérateur doit-il être une classe distincte ?
Non, si la base de données des éléments prend en charge l'énumérateur standard (par exemple, si vous agrégerez List(Of T)), vous pouvez retourner son GetEnumerator. Ce n'est que dans des scénarios complexes qu'un propre classe implémentant IEnumerator peut être nécessaire.
Est-il possible de modifier la collection à l'intérieur de la boucle For Each ?
Non, la modification de la collection pendant l'itération entraînera une InvalidOperationException. Pour un traitement correct, des stratégies spéciales sont nécessaires (par exemple, copier la liste avant l'itération ou utiliser l'indexation).
Dans l'entreprise, une classe MyCollection a été développée avec ajout et suppression via un tableau, mais sans implémenter l'interface IEnumerable. For Each ne fonctionnait pas, il fallait utiliser des boucles ordinaires et un champ public avec des éléments.
Avantages :
Inconvénients :
La classe a été refondue, en implémentant IEnumerable(Of T). Après cela, la collection a pu être utilisée facilement et de manière standard avec For Each, et est devenue compatible avec LINQ.
Avantages :
Inconvénients :