foreach和IEnumerable之间的联系是什么?

时间:2014-01-31 01:09:35

标签: c# foreach ienumerable ienumerator

  

foreach语句为数组中的每个元素或实现System.Collections.IEnumerableSystem.Collections.Generic.IEnumerable<T>接口的对象集合重复一组嵌入式语句。

我理解如果我们想在对象集合上使用foreach,我们需要在其上实现IEnumerable。

我想了解IEnumerable中的实现如何启用'foreach'的使用?

IEnumerable的源代码似乎只有一个函数'GetEnumerator',显然没有实现,因为IEnumerable是一个接口 - 那么foreach关键字如何实际使用IEnumerable接口进行枚举?

修改: 在这种情况下也试图理解它:

IEnumerable<Int> myNumbers = new IEnumerable<Int>();

这里调用/使用哪个GetEnumerator()?

编辑2:

所以答案似乎是:
    1:DuckTyping - (感谢@Alexei Levenkov。我接受@horrorcat作为答案,因为我只能接受一个:))
    2.我试图创建一个接口的具体实例(在我的问题的第二部分)中犯了一个明显的错误 - (感谢@Gary Vass)

4 个答案:

答案 0 :(得分:1)

foreach调用IEnumerable.GetEnumerator()(如果集合实现了一个)或查找返回duck-typed matching iterator classGetEnumerator()方法。

使用GetEnumerator()调用的结果迭代元素,将每个元素转换为foreach的第一个参数中指定的类型。

答案 1 :(得分:1)

IEnumerable.GetEnumerator()返回一个枚举器对象(实现IEnumerator)。它有一个返回当前项的属性“Current”,以及一个方法“MoveNext()”,它将枚举器推进到下一个项目。

这是执行foreach所需的所有foreach循环。它只是将“Current”属性赋给变量,然后每次执行.MoveNext()。

通常,当您在类上实现IEnumerable时,您知道源的来源。所以,如果你有一个像这样的课程

public class MyEnumerable
{
    private List<string> items;
}

IEnumerable的实现看起来像这样

public class MyEnumerable : IEnumerable<string>
{
    private List<string> items;

    public IEnumerator<string> GetEnumerator()
    {
        return items.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return items.GetEnumerator();
    }
}

请注意,枚举器来自列表对象,因此您不必担心创建枚举器(尽管您可以通过实现IEnumerator来实现)

答案 2 :(得分:0)

正如Lukazoid所说:“IEnumerable的实现者实现了方法GetEnumerator(),foreach调用此方法,然后使用生成的IEnumerator迭代元素。”

foreach仅使用接口IEnumerable / IEnumerable&lt;&gt;,我认为这是用于编写'readonly'for循环的C#快捷方式,您可以使用该数据但不能编辑它。

我也发现了这一点,这里是stackoverflow //which may make this question a dup

What's going on behind the scene of the 'foreach' loop?

答案 3 :(得分:0)

Foreach只是使用IEnumerable类型的语法糖。代码如:

foreach (var item in collection)
{
    ...
}

由编译器翻译为:

using (var enumerator = collection.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        var item = enumerator.Current;
        // loop contents here
    }
}