zoukankan      html  css  js  c++  java
  • C#枚举器:foreach语句、IEnumerable、IEnumerator以及yield return (一)

    using System;
    using System.Collections;

    C#中,我们通常可以用foreach语句来遍历数组或集合,下面深入探讨一下其工作原理 

    ①自定义集合MyList

        为了说明使用IEnumerable和IEnumerator接口,从而让数组或集合支持foreach语句的原理,我们首先自定义一个简单的链表形集合MyList,其中仅实现了AddData方法,其他相关方法没有写出,代码如下:

    //集合包含的项,即所谓的节点
    public class DataItem
    {
        public DataItem Next { get; set; }
        public object Data { get; set; }
        public DataItem(object data)
        {
            this.Data = data;
        }
    }
    //自定义集合类
    public class MyList
    {
        public DataItem FirstItem { get; set; }
        public DataItem LastItem { get; set; }
    
        public void AddData(object data)
        {
            DataItem newItem = new DataItem(data);
            if (this.FirstItem == null)
            {
                this.FirstItem = newItem;
                this.LastItem = newItem;
            }
            else
            {
                this.LastItem.Next = newItem;
                this.LastItem = newItem;
            }
        }
    }

    ②IEnumerable接口

        foreach在遍历集合的时候,实质上调用的是GetEnumerator方法,因此要使得集合支持foreach遍历,必须实现GetEnumerator方法,该方法定义在IEnumerable接口中,该接口定义如下:

    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

        

    ③IEmunerator接口

        因此只要让MyList继承IEnumerable接口,并实现GetEnumerator方法即可,可是该方法要求返回一个IEnumerator,现在我们还没任何地方实现这个IEmunerator接口,因此我们先来看看他的定义

    public interface IEnumerator
    {
         //集合中的当前元素。
        object Current { get; }
     
        //如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。
        bool MoveNext();
     
        //将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。
        void Reset();
    }

       

    ④实现IEnumerator接口

         从该接口的定义可以看出,foreach语句就是根据MoveNext方法和Current属性,一个一个遍历集合元素的,为了使得思路清晰,这里我们单独编写一个类来实现该接口,且该类会以上面的MyList为基础,以便MyList调用它

    public class MyEnumerator:IEnumerator
    {
        private DataItem currentItem = new DataItem(null);
        public MyEnumerator (MyList list) //使用MyList的实例来构造该类
        {
            this.currentItem.Next = list.FirstItem;
        }
        public object Current
        {
            get { return currentItem.Data; }
        }
        public bool MoveNext()
        {
            if(currentItem.Next != null)
            {
                currentItem = currentItem.Next;
                return true;
            }
            else
            {
                return false;
            }
        }
        public void Reset()
        {
            throw new NotImplementedException();
        }
    }

       

    ⑤实现IEnumerable接口

        有了这个MyEnumerator后,就可以让MyList实现IEnumerable接口中的GetEnumerator方法了,向MyList中添加如下代码

    public IEnumerator GetEnumerator()
    {
        return new MyEnumerator(this);
    }

       到此为止,虽然MyList的功能还十分不完善,但已经支持foreach语句遍历了,需要说明一点的是,不论MyList是否继承接口IEnumerable,只要实现了GetEnumerator方法,就可以支持foreach语句。

    ⑥yield return

        上面整个过程对于演示foreach语句的原理相当有用,不过每次都这样去实现就太费劲了,C#中可以使用yield return语句来帮我们自动实现IEnumerator接口,一下使得工作轻松多了,对MyList中的GetEnumerator方法作如下修改即可抛弃繁琐的MyEnumerator了

    public IEnumerator GetEnumerator()
    {
        //return new MyEnumerator(this);
        DataItem curent = this.FirstItem;
        while(curent != null)
        {
            yield return curent.Data;
            curent = curent.Next;
        }
    }
  • 相关阅读:
    rest framework 认证 权限 频率
    rest framework 视图,路由
    rest framework 序列化
    10.3 Vue 路由系统
    10.4 Vue 父子传值
    10.2 Vue 环境安装
    10.1 ES6 的新增特性以及简单语法
    Django 跨域请求处理
    20190827 On Java8 第十四章 流式编程
    20190825 On Java8 第十三章 函数式编程
  • 原文地址:https://www.cnblogs.com/ArtofDesign/p/3612492.html
Copyright © 2011-2022 走看看