[c#]foreach的原理

foreach本质上是迭代的使用,学习过程中发现它和c中的地址定位差不多,也是通过游标的不断移动获取当前所指向的数据。迭代器可以用一种方式,顺序访问集合类型(数组、字典、队列....)元素。

 

简单演示一下:

有一个接口IThrowable,其下有两个继承类GrenadeDarts;类Hand下有一个数组,其中包含GrenadeDarts

class Hand:IEnumerable

{

   public IThrowable[] AllObject { get; set; }

}

 

Main中实例化一个Hand对象:

static void Main(string[] args)

{

    Hand hand = new Hand()

    {

       AllObject = new IThrowable[2]//可投掷物接口,下有两个类手雷和飞镖

       {

             new Grenade(),

             new Darts()

       }

    };

}

 

此时我们使用迭代器来获取Hand中的所有对象,所以Main应该是

static void Main(string[] args)

{

    Hand hand = new Hand()

    {

        AllObject = new IThrowable[2]//可投掷物接口,下有两个类手雷和飞镖

        {

            new Grenade(),

            new Darts()

        }

    };

 

    //1.获取迭代器

    IEnumerator iterator = hand.GetEnumerator();

    //2.移动到下一个元素

    while (iterator.MoveNext())

    {

        //3.获取元素

        Console.WriteLine(iterator.Current);

    }

 

    Console.ReadKey();

}

 

到这里就会发现迭代器的使用主要就是在GetEnumerator()这个方法,它的返回值是枚举器,也就是我们所理解的游标。所以在Hand中我们需要实现下它的功能:

class Hand:IEnumerable

{

    public IThrowable[] AllObject { get; set; }

 

    //传统写法

    public IEnumerator GetEnumerator()

    {

        //创建迭代器对象

        return new HandEnumerator() { Target = AllObject };

    }

}

 

这里的HandEnumerator就是生成一个枚举器所用的迭代器

//传统写法

//类的迭代器,以Hand为例

class HandEnumerator : IEnumerator

{

    public IThrowable[] Target { get; set; }

    private int index;

 

    //获取当前数据

    public object Current

    {

        get { return Target[index]; }

    }

 

    //移动到下一个数据

    public bool MoveNext()

    {

        index++;

        return index <= Target.Length - 1;

    }

 

//未用到暂时不写

    public void Reset()

    { }

}

 

注意上面所注释的是传统的创建迭代器和使用方法,由于有yield关键字的存在,我们将yieldreturn结合一下,就可以将代码缩简为:

class Hand:IEnumerable

{

  //优化写法

    public IEnumerator GetEnumerator()

    {

        /*

         * 将yield以前的代码分配到MoveNext方法中

         * 将return后的数据分配到Current属性中

         */

        for (int i = 0; i < AllObject.Length; i++)

        {

            yield return AllObject[i];//返回数据 退出方法

        }

   }

}

这样我们就可以将繁琐的HandEnumerator 一起省去了。

运行测试下:

 

posted @ 2020-12-08 21:38  穷在闹市  阅读(225)  评论(0)    收藏  举报