Condividi tramite


Procedura: accedere a una classe di insiemi con foreach (Guida per programmatori C#)

Aggiornamento: novembre 2007

Nell'esempio di codice riportato di seguito viene illustrato come scrivere una classe Collection non generica utilizzabile con foreach. La classe è un tokenizer di stringa, analogo alla funzione C standard strtok_s.

Nota:

La procedura riportata in questo esempio è consigliata solo quando non è possibile utilizzare una classe Collection generica. I generics sono supportati nella versione 2.0 e successive del linguaggio C# e di .NET Framework. Per un esempio relativo all'implementazione di una classe Collection generica indipendente dai tipi che supporta IEnumerable<T>e pertanto evita i problemi descritti in questo argomento, vedere Procedura: creare un blocco iteratore per un elenco generico (Guida per programmatori C#).

Nell'esempio riportato di seguito Tokens suddivide la frase "This is a sample sentence." in token, utilizzando ' ' e '-' come separatori, ed enumera tali token con l'istruzione foreach:

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

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

Al suo interno Tokens utilizza una matrice che implementa IEnumerator e IEnumerable. Nell'esempio di codice sarebbe stato possibile utilizzare i metodi di enumerazione della matrice come metodi propri, ma questo avrebbe annullato lo scopo dell'esempio.

In C#, non è assolutamente necessario che una classe Collection erediti da IEnumerable e IEnumerator per essere compatibile con foreach. Se la classe dispone dei membri GetEnumerator, MoveNext, Reset e Current obbligatori, funzionerà con foreach. L'omissione delle interfacce consente di definire come tipo restituito da Current un tipo più specifico di Object, garantendo così l'indipendenza dai tipi.

Modificare ad esempio le righe che seguono nell'esempio di codice riportato in precedenza in questo argomento:

// 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  

Poiché Current restituisce una stringa, il compilatore è in grado di rilevare l'eventuale utilizzo di tipi non compatibili in un'istruzione foreach:

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

Tuttavia, l'omissione di IEnumerable e IEnumerator impedisce l'interoperabilità della classe Collection con le istruzioni foreach (o equivalenti) di altri linguaggi compatibili con Common Language Runtime.

È possibile ottenere entrambi i vantaggi, ossia indipendenza dai tipi all'interno di C# e interoperabilità con altri linguaggi compatibili con Common Language Runtime, ereditando da IEnumerable e IEnumerator e utilizzando l'implementazione esplicita dell'interfaccia, come illustrato nell'esempio seguente.

Esempio

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.  
*/

Vedere anche

Concetti

Guida per programmatori C#

Riferimenti

Matrici (Guida per programmatori C#)

Classi di insiemi (Guida per programmatori C#)

System.Collections.Generic

Altre risorse

Riferimenti per C#