开发者

Why in this example (got from msdn), in GetEnumerator method , new PeopleEnum returns IEnumerator?

Why in this example from MSDN, in GetEnumerator method, PeopleEnum returns 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()
{
    posi开发者_开发问答tion = -1;
}

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

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

UPDATE: BTW, if Array data type implements ICloneable interface, why msdn has copied pArray to _people by writing a for loop?


It needs to return exactly IEnumerator to properly implement the IEnumerable interface. It is doing this using an "explicit interface implementation", so on the public API you see PeopleEnum, but IEnumerable is still happy

But in reality you would very rarely write an enumerator this way in C# 2.0 or above; you'd use an iterator block (yield return). See C# in Depth chapter 6 (free chapter!).

For info, the reason that PeopleEnum exists at all here is that this looks like a .NET 1.1 sample, where that is the only way to create a typed enumerator. In .NET 2.0 and above there is IEnumerable<T> / IEnumerator<T>, which has a typed (via generics) .Current.

In .NET 2.0 / C# 2.0 (or above) I would have simply:

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


Types implementing IEnumerable require a method called GetEnumerator that returns an IEnumerator. In that example (which is pretty obsolete as of C# 2.0) there is an enumerator class PeopleEnum that implements IEnumerator. It's what's used internally by the C# foreach statement.

A more up to date example would look more like the following. Note there's no longer a need for a PeopleEnum class now that C# supports iterators. Effectively the compiler does all the heavy lifting for you.

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];
       }
   }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜