foreach遍历数据,数据类型之所以能进行遍历,是应为这个数据类型继承了接口IEnumerable

并且这个数据类型内部一般都有一个自己独有的枚举器继承自枚举器接口IEnumerator

这个枚举器有三个方法

public object Current;当前对象

public bool MoveNext();下一个,让下标下移

public void Reset();重置下标

自己定义的类也可以实现这个接口来实现使用foreach来循环数组

示例为Person5

foreach在编译之后,都会被替换成调用对应的枚举器里面的方法

可以把foreach理解为调用枚举器的一个代码简写方式

如下为代码示例

public class foreach遍历数据
     {

         //凡是具有GetEnumerator这个方法的类型,都可以使用foreach进行数据的遍历
         //其实通过foreach遍历数据,实际上是调用了一个“枚举器”来遍历数据,和foreach一点关系都没有,foreach只是一个语法上的简化而已
         //通过使用foreach只是降低了枚举数据使用的复杂度


         public static void GetFor()
         {
             Console.WriteLine("使用索引器来遍历");
             Person4 p = new Person4();
             for (int i = 0; i < p.Coun; i++)
             {
                 Console.WriteLine(p[i]);
             }


             Console.WriteLine("=========================================");
             Console.WriteLine("使用枚举器接口来实现");
             //手动调用枚举器
             Person5 pp = new Person5();
             IEnumerator enumtor = pp.GetEnumerator();
             while (enumtor.MoveNext())
             {
                 Console.WriteLine(enumtor.Current.ToString());
             }

             Console.WriteLine("=========================================");
             //或者使用foreach自动调用枚举器
             Person5 ppp = new Person5();
             //foreach (string item in ppp)
             //{
             //    Console.WriteLine(item);
             //}
             //也可以使用var来推断类型,但是这里鼠标点上去的时候可以看到这里推断出来的是System.Object类型,而不是string
             //这是应为枚举器接口IEnumerator中的public object Current方法返回的的就是Object类型
             //所以这里推断出来的才是object类型
             foreach (var item in ppp)
             {
                 Console.WriteLine(item);
             }

             Console.WriteLine("=========================================");
             Console.WriteLine("使用yield return和返回类型IEnumerable来实现");
             Person6 p6 = new Person6();
             foreach (var item in p6.GetEnumObj())
             {
                 Console.WriteLine(item);
             }


             Console.WriteLine("=========================================");
             Console.WriteLine("使用yield return和接口类型IEnumerable来实现");
             Person7 p7 = new Person7();
             foreach (var item in p7)
             {
                 Console.WriteLine(item);
             }
         }

     }


     /// <summary>
     /// 使用索引器的来实现使用for来循环数据
     /// </summary>
     public class Person4
     {
         /// <summary>
         /// 定义一个私有的数组
         /// </summary>
         private string[] Friends = new string[] { "彭德怀", "毛泽东", "周恩来", "朱德", "刘少奇" };

         /// <summary>
         /// 创建一个索引器
         /// </summary>
         /// <param name="index"></param>
         /// <returns></returns>
         public string this[int index]
         {
             get
             {
                 return Friends[index];
             }
             set
             {
                 Friends[index] = value;
             }
         }

         /// <summary>
         /// 创建一个属性,返回数组长度
         /// </summary>
         public int Coun
         {
             get
             {

                 return Friends.Length;
             }
         }
     }


     /// <summary>
     ///
     /// 1.需要让该类实现IEnumerable接口,实现该接口的目的是为了让当前类型中增加方法GetEnumerator
     /// 这里只要有方法GetEnumerator就可以了,就算不实现接口IEnumerable也可以直接添加上去
     /// </summary>
     public class Person5 : IEnumerable
     {
         /// <summary>
         /// 定义一个私有的数组
         /// </summary>
         private string[] Friends = new string[] { "彭德怀", "毛泽东", "周恩来", "朱德", "刘少奇" };


         /// <summary>
         /// 这里返回的就是一个枚举器
         /// </summary>
         /// <returns></returns>
         public IEnumerator GetEnumerator()
         {
             //返回枚举器,传入构造函数的参数为需要处理的数据
             return new PersonEnumerator(Friends);
         }
     }
     /// <summary>
     /// 这个类型就是“枚举器”
     /// 如果希望一个类型可以被“枚举”,“遍历”,就要实现一个类,这个类就是“枚举器”
     /// </summary>
     public class PersonEnumerator : IEnumerator
     {
         /// <summary>
         /// 操作的数据
         /// </summary>
         private string[] _friends;

         /// <summary>
         /// 集合的下标
         /// 下标一般指向数组汇总第一条的前一个
         /// </summary>
         private int index = -1;

         /// <summary>
         /// 构造函数,入参为需要操作的数据
         /// </summary>
         /// <param name="strAry"></param>
         public PersonEnumerator(string[] strAry)
         {
             this._friends = strAry;
         }



         /// <summary>
         /// 当前对象
         /// </summary>
         public object Current
         {
             get
             {
                 if (index >= 0 && index < _friends.Length)
                 {
                     return _friends[index];
                 }
                 else
                 {
                     //抛出数组越界的错误
                     throw new IndexOutOfRangeException();
                 }
             }
         }

         /// <summary>
         /// 向下移动
         /// </summary>
         /// <returns></returns>
         public bool MoveNext()
         {
             //在这里如果达到数组的最后一条数据的时候,直接停留在最后一个数据
             //这里不要重置为第一个数据,重置交给方法Reset来处理
             if (index + 1 < _friends.Length)
             {
                 index++;
                 return true;
             }
             return false;
         }

         /// <summary>
         /// 重置下标
         /// </summary>
         public void Reset()
         {
             index = -1;
         }
     }


     /// <summary>
     /// 使用yield return和返回类型IEnumerable类实现遍历
     /// </summary>
     public class Person6
     {
         /// <summary>
         /// 这里的名称是随便起的
         /// </summary>
         /// <returns></returns>
         public IEnumerable GetEnumObj()
         {
             for (int i = 0; i < Friends.Length; i++)
             {
                 yield return Friends[i];
             }
         }

         /// <summary>
         /// 定义一个私有的数组
         /// </summary>
         private string[] Friends = new string[] { "彭德怀", "毛泽东", "周恩来", "朱德", "刘少奇" };
     }



     /// <summary>
     /// 这里在实现玩接口IEnumerable之后可以把这个实现给去掉
     /// 只要里面有方法public IEnumerator GetEnumerator()就可以了
     /// </summary>
     public class Person7 : IEnumerable
     {
         /// <summary>
         /// 定义一个私有的数组
         /// </summary>
         private string[] Friends = new string[] { "彭德怀", "毛泽东", "周恩来", "朱德", "刘少奇" };


         public IEnumerator GetEnumerator()
         {
             for (int i = 0; i < Friends.Length; i++)
             {
                 yield return Friends[i];
             }
         }
     }