¿Por qué en este ejemplo (obtuvo de MSDN), en el método GetEnumerator, nuevo PeopleEnum vuelve IEnumerator?

StackOverflow https://stackoverflow.com/questions/2635219

  •  26-09-2019
  •  | 
  •  

Pregunta

¿Por qué en este ejemplo de MSDN, en el método GetEnumerator, devoluciones PeopleEnum IEnumerator?

public class Person
{
    public Person(string fName, string lName)
    {
        this.firstName = fName;
        this.lastName = lName;
    }

    public string firstName;
    public string lastName;
}

public class People : IEnumerable
{
    private Person[] _people;
    public People(Person[] pArray)
    {
        _people = new Person[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _people[i] = pArray[i];
        }
    }
   //why??? 
   IEnumerator IEnumerable.GetEnumerator()
   {
       return (IEnumerator) GetEnumerator();
   }

   public PeopleEnum GetEnumerator()
   {
       return new PeopleEnum(_people);
   }
}

public class PeopleEnum : IEnumerator
{
    public Person[] _people;

// Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1;

public PeopleEnum(Person[] list)
{
    _people = list;
}

public bool MoveNext()
{
    position++;
    return (position < _people.Length);
}

public void Reset()
{
    position = -1;
}

object IEnumerator.Current
{
    get
    {
        return Current;
    }
}

public Person Current
{
    get
    {
        try
        {
            return _people[position];
        }
        catch (IndexOutOfRangeException)
        {
            throw new InvalidOperationException();
        }
    }
}

ACTUALIZACIÓN: Por cierto, si el tipo de datos Array implementa la interfaz ICloneable, ¿por qué MSDN ha copiado pArray a _people escribiendo un bucle?

¿Fue útil?

Solución

Se necesita volver exactamente IEnumerator para aplicar correctamente la interfaz IEnumerable. Se hace esto usando una "implementación de interfaz explícita", por lo que en el público API ves PeopleEnum, pero IEnumerable sigue siendo feliz

Pero, en realidad, que sería muy raramente escribir un enumerador de esta manera en C # 2.0 o superior; tendrá que utilizar un bloque de iterador (yield return). Ver C # en profundidad capítulo 6 (capítulo gratis!).

Para obtener información, la razón por la que existe PeopleEnum en absoluto aquí es que esto parece un ejemplo de .NET 1.1, en que es la única manera de crear un enumerador con tipo. En .NET 2.0 y superior hay IEnumerable<T> / IEnumerator<T>, que tiene una mecanografiada (a través de los genéricos) .Current.

En .NET 2.0 / C # 2.0 (o superior) Me gustaría tener simplemente:

public class People : IEnumerable<Person> {
    /* snip */
    public IEnumerator<Person> GetEnumerator() {
        return ((IEnumerable<Person>)_people).GetEnumerator();
    }
    IEnumerator IEnumerable.GetEnumerator() { return _people.GetEnumerator();}
}

Otros consejos

Tipos de aplicación IEnumerable requieren un método llamado GetEnumerator que devuelve un IEnumerator. En ese ejemplo (que es bastante obsoleto como de C # 2.0) hay un PeopleEnum clase empadronador que implementa IEnumerator. Es lo que se utiliza internamente por la declaración de C # foreach.

A más hasta la fecha de ejemplo se parecería más a la siguiente. Nota Ya no hay una necesidad de una clase PeopleEnum ahora que C # admite iteradores. Efectivamente el compilador hace todo el trabajo pesado para usted.

public class People : IEnumerable
{
    private Person[] _people;
    public People(Person[] pArray)
    {
        _people = new Person[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _people[i] = pArray[i];
        }
    }

   IEnumerator IEnumerable.GetEnumerator()
   {
       for (int i=0; i < _people.Length; i++) {
           yield return _people[i];
       }
   }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top