Compartir a través de


Cómo: Obtener acceso a una clase de colección mediante Foreach (Guía de programación de C#)

Actualización: noviembre 2007

En el ejemplo de código siguiente se muestra cómo escribir una clase de colección no genérica que se pueda utilizar con la instrucción foreach. La clase es un analizador de cadenas, similar a la función strtok_s de la biblioteca en tiempo de ejecución de C.

Nota:

Este ejemplo representa la práctica recomendada sólo cuando no se puede utilizar una clase de colección genérica. Los genéricos se admiten en la versión 2.0 y posteriores del lenguaje C# y .NET Framework. Para obtener un ejemplo de cómo implementar una clase de colección genérica con seguridad de tipos que admite IEnumerable<T>y, en consecuencia, impide que se produzcan los problemas que se describen más adelante en este tema, consulte Cómo: Crear un bloque de iteradores para una lista genérica (Guía de programación de C#).

En el ejemplo siguiente, Tokens divide la oración "This is a sample sentence." en tokens utilizando los separadores ' ' y '-', y enumera esos símbolos con la instrucción foreach:

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

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

Internamente, Tokens utiliza una matriz, la cual implementa IEnumerator e IEnumerable. El ejemplo de código podría haber utilizado los métodos de enumeración de la matriz, pero eso iría en contra del propósito de este ejemplo.

En C#, no es absolutamente necesario que una clase de colección herede de IEnumerable y IEnumerator para que pueda ser compatible con foreach. Siempre que la clase disponga de los miembros GetEnumerator, MoveNext, Resety Current requeridos, funcionará con foreach. Omitir las interfaces tiene la ventaja de que permite definir el tipo de valor devuelto de Current de modo que sea más específico que Object, lo que proporciona seguridad de tipos.

Por ejemplo, al principio del código de ejemplo anterior de este tema, cambie las líneas siguientes:

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

Ahora, debido a que Current devuelve una cadena, el compilador puede detectar cuándo se utiliza un tipo incompatible en una instrucción foreach:

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

El inconveniente de omitir IEnumerable e IEnumerator es que la clase de colección ya no puede interactuar con las instrucciones foreach (o equivalentes) de otros lenguajes compatibles con Common Language Runtime.

Puede combinar lo mejor de ambos enfoques (seguridad de tipos de C# e interoperabilidad con otros lenguajes compatibles con Common Language Runtime) si hereda de IEnumerable e IEnumerator, y utiliza implementación de interfaces explícita, tal como se muestra en el ejemplo siguiente.

Ejemplo

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

Vea también

Conceptos

Guía de programación de C#

Referencia

Matrices (Guía de programación de C#)

Clases de colección (Guía de programación de C#)

System.Collections.Generic

Otros recursos

Referencia de C#