困惑于实现IEnumerable

时间:2014-08-15 16:59:59

标签: c#

我引用MSDN中的示例如下,

using System;
using System.Collections;

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

    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();
            }
        }
    }
}

class App
{
    static void Main()
    {
        Person[] peopleArray = new Person[3]
        {
            new Person("John", "Smith"),
            new Person("Jim", "Johnson"),
            new Person("Sue", "Rabon"),
        };

        People peopleList = new People(peopleArray);
        foreach (Person p in peopleList)
            Console.WriteLine(p.firstName + " " + p.lastName);

    }
}

/* This code produces output similar to the following:
 *
 * John Smith
 * Jim Johnson
 * Sue Rabon
 *
 */

问题

  1. Person[] ctor中复制People的原因是什么?

  2. 为什么People通过新的重载方法GetEnumerator返回PeopleEnum来实现public PeopleEnum GetEnumerator()?是否一定需要新方法public PeopleEnum GetEnumerator()

  3. 使用相同的模式,为什么PeopleEnum通过新属性Current返回Person来实现public Person Current?是否一定需要新属性public Person Current

  4. 我的代码(用于比较)

    using System;
    using System.Collections;
    
    namespace ExtensionMethod
    {
    
        sealed class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    
        sealed class PeopleEnumerator : IEnumerator
        {
            Person[] people;
            int position = -1;
    
            public PeopleEnumerator(Person[] people)
            {
                this.people = people;
            }
    
            bool IEnumerator.MoveNext()
            {
                position++;
                return position < people.Length;
            }
    
            object IEnumerator.Current
            {
                get
                {
                    return people[position];
                }
            }
    
            void IEnumerator.Reset()
            {
                position = -1;
            }
        }
    
        sealed class People : IEnumerable
        {
            private Person[] people;
    
            public People(Person[] people)
            {
                this.people = people;
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return new PeopleEnumerator(people);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                People people = new People(
                    new[]{
                        new Person {Name="Andy",Age=23},
                        new Person {Name="Bobby",Age=22}
               });
    
                foreach (Person p in people)
                    Console.WriteLine(p.Name);
            }
        }
    }
    

1 个答案:

答案 0 :(得分:1)

  

Person[]构造函数中复制People的原因是什么?

因为如果您存储了引用,那么对源数组的任何更改都将反映在集合中。通过复制项目,您可以将集合与源分离。

  

为什么People通过新的重载方法GetEnumerator返回PeopleEnum来实现public PeopleEnum GetEnumerator()?是否一定需要新方法public PeopleEnum GetEnumerator()

重载提供了一个强类型枚举器,而不是基本的IEnumerator接口。这允许foreach返回集合中的实际类型而不转换为对象(如果基础类型是值类型,则为装箱)

  

使用相同的模式,为什么PeopleEnum通过新属性Current返回Person来实现public Person Current?是否一定需要新属性public Person Current

出于同样的原因 - 所以foreach可以返回实际类型而不进行强制转换(或装箱)

从本质上讲,foreach将使用“duck typing”并使用强类型GetEnumeratorNextCurrent代替IEnumerator接口方法

您可以在foreach上阅读Eric Lippert's article,以便更好地了解鸭子类型和强类型枚举器的价值。