Foreach遍历 IEnumerable 使用foreach 详解 IEnumerator和IEnumerable的关系 先说IEnumerable,咱们天天用的foreach你真的懂它吗?

前天在项目中遇到一个问题,foreach遍历过程当中修改responses中的对象,其中responses的类型:IEnumerable<Order>,代码以下:html

foreach (Order item in responses)
            {
                if (string.IsNullOrEmpty(item.Creator))
                    item.Creator = item.Creator2;
            }

结果可想而知,response的对象并无被改变。这是为何?数组

 

弄清楚问题以前须要明白什么是foreach。foreach语句为数组或者对象集合的每个元素重复一个嵌入语句组,foreach语句用于循环访问集合以获取所需信息,但不该更改集合信息以免不可预知的负做用。(百度百科)Foreach能够循环访问集合以获取所需信息,为何foreach不能更改集合信息,什么样的对象可以foreach?这就涉及到IEnumerable和IEnumerator.数据结构

 

IEnumerable和IEnumerator是两个用来实现枚举的接口,相互协助来完成一个具备枚举功能能使用foreach的集合。IEnumerable是一个声明性接口,一个集合对象要foreach,必须实现IEnumerable接口,也既是必须以某种方式返回IEnumerator object。IEnumerator是一个实现式接口,它定义了具体的实现方法。下面首先介绍其定义:post

定义IEnumerator接口:this

public interface IEnumerator
    {
        object Current{ get; }

        bool MoveNext();
        void Reset();
    }

 定义IEnumerable接口:url

public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

 

了解定义后,下面实例具体实现IEnumerable和IEnumerator:spa

public class MyIEnumerator : IEnumerator
    {
        private string[] strList;
        private int position;

        public MyIEnumerator(string[] strList)
        {
            this.strList = strList;
            position = -1;
        }

        public object Current
        {
            get { return strList[position]; }
        }

        public bool MoveNext()
        {
            position ++;
            if (position < strList.Length) return true;
            return false;
        }

        public void Reset()
        {
            position = -1;
        }
    }

 

public class MyIEnumerable : IEnumerable
    {
        private string[] strList;

        public MyIEnumerable(string[] strList)
        {
            this.strList = strList;
        }
        public IEnumerator GetEnumerator()
        {
            return new MyIEnumerator(strList);
        }
    }

 

进行调用:3d

string[] strList = {"1", "2", "4", "8"};
            MyIEnumerable my = new MyIEnumerable(strList);

            var tt = my.GetEnumerator();
            while (tt.MoveNext())
            {
                Console.Write("{0} ", tt.Current);
            }

 

结果以下:code

 

 

那么在项目中,如何自定义一个类实现foreach,继承IEnumerable便可,以下实例:htm

定义实体类:

public class Student
    {
        public int Id;
        public string Name;

        public Student(int id, string name)
        {
            Id = id;
            Name = name;
        }
    }

 

定义student的集合类School,继承IEnumerable集合:

public class School : IEnumerable
    {
        public Student[] stu = new Student[3];

        public School()
        {
            Create();
        }

        public void Create()
        {
            stu[0] = new Student(1, "tom");
            stu[1] = new Student(2, "john");
            stu[2] = new Student(3, "mali");
        }

        public IEnumerator GetEnumerator()
        {
            return this.stu.GetEnumerator();
        }
    }

 

使用foreach遍历school:

School school = new School();

            foreach (Student item in school.stu)
            {
                Console.WriteLine("Id is {0} ,Name is {1}", item.Id, item.Name);
            }

            foreach (Student item in school)
            {
                Console.WriteLine("Id is {0} ,Name is {1}", item.Id, item.Name);
            }

 

结果以下:

 

此时一个概念“迭代器”应该进入你们的视野。

 迭代器是一种对象,它可以用来遍历标准模板库容器的部分或者所有元素,每一个迭代器对象表明容器中的肯定地址。

迭代器使开发人员可以在类或者结构中支持foreach迭代,而没必要整个实现IEnumerable和IEnumerator接口。只须要提供一个迭代器,便可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable和IEnumerator接口中的相应方法。

 

另一个概念yield:yield关键字向编译器指示它所在的方法是迭代器。编译器生成一个类来实现迭代器块中表示的行为。在迭代器块中,yield关键字与return关键字结合使用,向枚举器对象提供值。yield关键字也可与break结合使用,表示迭代结束。

 

引用:

IEnumerable 使用foreach 详解

IEnumerator和IEnumerable的关系

 

先说IEnumerable,咱们天天用的foreach你真的懂它吗?

相关文章
相关标签/搜索