zoukankan      html  css  js  c++  java
  • Foreach遍历

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

    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是一个实现式接口,它定义了具体的实现方法。下面首先介绍其定义:

    定义IEnumerator接口:

    public interface IEnumerator
        {
            object Current{ get; }
    
            bool MoveNext();
            void Reset();
        }

     定义IEnumerable接口:

    public interface IEnumerable
        {
            IEnumerator GetEnumerator();
        }

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

    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);
            }
        }

    进行调用:

    string[] strList = {"1", "2", "4", "8"};
                MyIEnumerable my = new MyIEnumerable(strList);
    
                var tt = my.GetEnumerator();
                while (tt.MoveNext())
                {
                    Console.Write("{0} ", tt.Current);
                }

    结果如下:

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

    定义实体类:

    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你真的懂它吗?

  • 相关阅读:
    第五十四天:jQuery内容的基础:
    第五十三天dom基础
    第五十二天js的&#183;进阶
    第五十一天js的基础
    第四十九天css进阶
    第四十八天 html中的form和css基础
    第四十七天:web中德html初级:
    第42天IO模块
    第四十一天:协程操作
    第四十天线程的进阶
  • 原文地址:https://www.cnblogs.com/ysyn/p/5915190.html
Copyright © 2011-2022 走看看