为什么在使用foreach迭代时不需要实现IEnumerable

时间:2016-03-05 19:03:35

标签: c# foreach ienumerable ienumerator

我正在查看IEnumerable并尝试this链接中给出的示例。我理解当我们使用foreach进行迭代时,GetEnumerator()方法会被调用,因为我的List类已经实现了IEnumerable(或者可能是我错了)。

   public class List<T> : IEnumerable
    {
        private T[] _collection;
        public List(T[] inputs)
        {
            _collection = new T[inputs.Length];
            for (int i = 0; i < inputs.Length; i++)
            {
                _collection[i] = inputs[i];
            }
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)GetEnumerator();
        }
        public CollectionEnum<T> GetEnumerator()
        {
            return new CollectionEnum<T>(_collection);
        }
    }

public class CollectionEnum<T> : IEnumerator
    {
        public T[] _collection ;
        int position = -1;
        public CollectionEnum(T[] list)
        {
            _collection = list;
        }
        public bool MoveNext()
        {
            position++;
            return (position < _collection.Length);
        }
        //implementation on Current and Reset
    }

然后,还提到使用IEnumerable进行迭代不需要foreach的实现。因此,在上面的代码中,如果删除IEnumerable的实现,则foreach必须正常工作。所以我的List<>课程看起来像

public class List<T>
{
    private T[] _collection;
    public List(T[] persons)
    {
        _collection = new T[persons.Length];
        for (int i = 0; i < persons.Length; i++)
        {
            _collection[i] = persons[i];
        }
    }
    public CollectionEnum<T> GetEnumerator()
    {
        return new CollectionEnum<T>(_collection);
    }
}

哪个确实有效。现在我不明白foreach如何知道我的班级有一个方法调用GetEnumerator(),它返回一个IEnumerator类型。

2 个答案:

答案 0 :(得分:2)

linked已向您remarks提供解释的文章。

  

如果您的收藏集未实现IEnumerable,您仍必须   通过提供a来遵循迭代器模式来支持这种语法   GetEnumerator方法,返回接口,类或结构 ....包含当前属性, MoveNext 重置方法为   由IEnumerator描述,但该类不必实现   IEnumerator

答案 1 :(得分:1)

正如Nkosi所提到的,在解释foreach时,编译器会查找最初在IEnumerable和IEnumerator中表示的模式。

早期版本的C#编译器需要实现这些接口。但是,随着LINQ的出现,语言和编译器已经过调整,可以更好地识别模式。

例如,您可以围绕具有Where方法但不实现IEnumerable的对象创建LINQ查询。

同样,您可以等待Awaitable Pattern之后的任何对象,而不仅仅是Task或Task。

一旦你理解了编译器正在寻找满足模式的特定方法,就会更容易理解为什么foreach不需要IEnumerable。还要记住,foreach实际上只是遍历一组对象的语法糖。