Partager via


Comment : accéder à une classe de collection à l'aide de foreach (Guide de programmation C#)

Mise à jour : novembre 2007

L'exemple de code suivant explique comment écrire une classe de collection non générique qui peut être utilisée avec foreach. La classe est un générateur de jetons de chaîne similaire à la fonction runtime C strtok_s.

Remarque :

Cet exemple représente uniquement la méthode recommandée dans les cas où vous ne pouvez pas utiliser de classe de collection générique. Les génériques sont pris en charge dans la version 2.0 et les versions ultérieures du langage C# et du .NET Framework. Pour obtenir un exemple d'implémentation d'une classe de collection générique de type sécurisé qui prend en charge IEnumerable<T> et ainsi évite les problèmes présentés ci-après, consultez Comment : créer un bloc itérateur pour une liste générique (Guide de programmation C#).

Dans l'exemple suivant, Tokens décompose la phrase "This is a sample sentence" en jetons en utilisant ' ' et '-' comme séparateurs, et énumère ces jetons avec l'instruction foreach :

Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

foreach (string item in f)
{
    System.Console.WriteLine(item);
}

En interne, Tokens utilise un tableau, qui implémente lui-même IEnumerator et IEnumerable. L'exemple de code aurait pu utiliser les méthodes d'énumération du tableau comme si elles étaient les siennes, mais cela serait contraire à l'objectif de cet exemple.

En C#, ce n'est pas absolument nécessaire pour une classe de collection à hériter de IEnumerable et IEnumerator pour soyez compatible avec foreach. Tant que la classe a le GetEnumerator requis, MoveNext, Reset et membres Current, cela fonctionnera avec foreach. L'omission des interfaces est intéressante dans la mesure où elle vous permet de définir un type de retour de Current plus spécifique que Object et d'assurer une sécurité de type.

Par exemple, reprenez l'exemple de code décrit plus haut dans cette rubrique et modifiez les lignes suivantes :

// No longer inherits from IEnumerable:
public class Tokens  
// Doesn't return an IEnumerator:
public TokenEnumerator GetEnumerator()  
// No longer inherits from IEnumerator:
public class TokenEnumerator  
// Type-safe: returns string, not object:
public string Current  

Maintenant, parce que Current retourne une chaîne, le compilateur peut détecter si un type incompatible est utilisé dans une instruction foreach :

// Error: cannot convert string to int:
foreach (int item in f)  

L'omission de IEnumerable et IEnumerator présente cependant un inconvénient : la classe collection ne peut plus fonctionner avec les instructions foreach, ou leurs équivalents, des autres langages compatibles avec le CLR (Common Language Runtime).

Vous pouvez bénéficier des avantages des deux univers, sécurité de type avec C# et interopérabilité avec les autres langages compatibles avec le CLR (Common Language Runtime), en héritant de IEnumerable et de IEnumerator, et en utilisant l'implémentation d'interface explicite, comme illustré dans l'exemple suivant.

Exemple

using System.Collections;

// Declare the Tokens class:
public class Tokens : IEnumerable
{
    private string[] elements;

    Tokens(string source, char[] delimiters)
    {
        // Parse the string into tokens:
        elements = source.Split(delimiters);
    }

    // IEnumerable Interface Implementation:
    //   Declaration of the GetEnumerator() method 
    //   required by IEnumerable
    public IEnumerator GetEnumerator()
    {
        return new TokenEnumerator(this);
    }


    // Inner class implements IEnumerator interface:
    private class TokenEnumerator : IEnumerator
    {
        private int position = -1;
        private Tokens t;

        public TokenEnumerator(Tokens t)
        {
            this.t = t;
        }

        // Declare the MoveNext method required by IEnumerator:
        public bool MoveNext()
        {
            if (position < t.elements.Length - 1)
            {
                position++;
                return true;
            }
            else
            {
                return false;
            }
        }

        // Declare the Reset method required by IEnumerator:
        public void Reset()
        {
            position = -1;
        }

        // Declare the Current property required by IEnumerator:
        public object Current
        {
            get
            {
                return t.elements[position];
            }
        }
    }


    // Test Tokens, TokenEnumerator
    static void Main()
    {
        // Testing Tokens by breaking the string into tokens:
        Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

        foreach (string item in f)
        {
            System.Console.WriteLine(item);
        }
    }
}
/* Output:
    This
    is
    a
    sample
    sentence.  
*/

Voir aussi

Concepts

Guide de programmation C#

Référence

Tableaux (Guide de programmation C#)

Classes de collection (Guide de programmation C#)

System.Collections.Generic

Autres ressources

Référence C#