C#枚举器:foreach语句、IEnumerable、IEnumerator以及yield return (二)

using System;
using System.Collections;

    关于使用IEnumerable、IEnumerator以及yield return来实现对foreach语句的支持,参见:《C#枚举器:foreach语句、IEnumerable、IEnumerator以及yield return (一)》

    本文主要是分析一下foreach语句本身:

foreach (var item in collection)
{
    //do someth  
}

    foreach语句要求遍历的对象collection实现GetEnumerator方法(这个方法定义在IEnumerable中),所以foreach语句工作时其实是转化成了如下语句来迭代collection中的每个元素的:

IEnumerator enumerator = colloction.GetEnumerator();
while(enumerator.MoveNext())
{
    var item = enumerator.Current;
    //do something
}

    事实上,这里的collection可以替换成任何实现了GetEnumerator()方法的对象,或者一个表达式且该表达最终返回一个实现了GetEnumerator()方法的对象,比如

//假设myArray.Reverse()返回一个继承自IEnumerable接口的对象,或者实现了GetEnumerator()方法的对象
foreach (var item in myArray.Reverse())
{
    //do something
}

    了解到这一点后,我们可以按照自己的想法去充分挖掘foreach迭代的用法,例如

public class Names:IEnumerable
{
    string[] names = { "David", "Peter", "Kunta", "Linda", "Bob" };
    //基本迭代
    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < 5; i++)
        {
            yield return names[i];
        }
    }
    //逆序迭代
    public IEnumerable Reverse()
    {
        for (int i = 4; i >= 0; i--)
        {
            yield return names[i];
        }
    }
    //部分迭代
    public IEnumerable Subset(int startIndex, int length)
    {
        for (int i = startIndex; i < startIndex + length; i++)
        {
            yield return names[i];
        }
    }
}

public class TestNames
{
    public static void Test()
    {
        var names = new Names();
        foreach (var name in names)//基本迭代的调用
        {
            Console.WriteLine(name);
        }
        foreach (var name in names.Reverse())//逆序迭代的调用
        {
            Console.WriteLine(name);
        }
        foreach (var name in names.Subset(2,2))//部分迭代的调用
        {
            Console.WriteLine(name);
        }
        Console.ReadKey();
    }
}

    按照前面的所说的:

    ①第一个基本迭代的对象是names,foreach会最终去调用names.GetEnumerator(),这种是我们定义在Names类中的方法;

    ②第二个逆序迭代的对象是names.Reverse(),该方法返回IEnumerable接口,肯定是实现了GetEnumerator()方法的,因此foreach语句会最终去调用names.Reverse().GetEnumerator(),而这里这个GetEnumerator()并不是我们在Names类中实现的方法,而是yield return语句自动生成的;

    ③第三个与第二个一样,foreach语句最终会调用names.Subset(2, 2).GetEnumerator();



原文地址:https://www.cnblogs.com/ArtofDesign/p/3612533.html