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

本文关键字:不需要 实现 IEnumerable 迭代 foreach 为什么 | 更新日期: 2023-09-27 18:37:28

我正在研究IEnumerable并尝试此链接中给出的示例。我知道当我们使用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怎么知道我的类有一个返回IEnumerator类型的方法调用GetEnumerator()

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

您链接到的文章已经在备注中为您提供了解释。

如果您的集合未实现 IEnumerable ,则仍必须 遵循迭代器模式,通过提供 GetEnumerator返回接口、类或结构的方法。包含当前属性,以及 MoveNext重置方法为 由IEnumerator描述,但类不必实现 IEnumerator .

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

早期版本的 C# 编译器需要实现这些接口。 但是,随着 LINQ 的出现,语言和编译器已进行调整,以执行更多识别模式的操作。

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

同样,您可以等待遵循可等待模式的任何对象,而不仅仅是任务或任务。

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