zoukankan      html  css  js  c++  java
  • foreach适合在什么情况下使用+foreach的内部原理剖析 Carl

    先看下面这段代码;foreach是可以遍历的。没有问题!

    1 ArrayList arrList1 = new ArrayList() { 20, 3, 49, 39, 48 };
    2          foreach (var item in arrList1)
    3             {
    4               Console.WriteLine(item);
    5             }

    这个也没有问题,可以正常的遍历

    1  string[] names = { "a", "b", "c", "d" };
    2            foreach (string item in names)
    3             {
    4               Console.WriteLine(item);
    5             }

    我们自己模拟一个类似于数组的对象

     1  public class Person : IEnumerable
     2     {
     3         private List<string> listCar = new List<string>();
     4 
     5         public int Count
     6         {
     7             get
     8             {
     9                 return this.listCar.Count;
    10             }
    11 
    12         }
    13 
    14         public string this[int index]
    15         {
    16             get
    17             {
    18                 return listCar[index];
    19             }
    20 
    21             set
    22             {
    23                 if (index >= listCar.Count)
    24                 {
    25                     listCar.Add(value);
    26                 }
    27                 else
    28                 {
    29                     listCar[index] = value;
    30                 }
    31             }
    32         }
    33 }

    好,这个时候我们来实例化这个person对象

    1   Person p = new Person();
    2             p[0] = "奇瑞QQ";
    3             p[1] = "infiniti";
    4             p[2] = "阿斯顿马丁";
    5             for (int i = 0; i < p.Count; i++)
    6             {
    7              Console.WriteLine(p[i]);
    8             }

    这个时候,也没有问题。能打印出结果!
    这个时候我们用foreach来遍历试试看

    1  foreach (string item in p)
    2             {
    3                 Console.WriteLine(item);
    4             }

    这个时候编译报错,提示不包含 “GetEnumerator”的公共定义

    这个GetEnumerator是什么呢?

      我们打开反编译工具:分别查找ArrayList,string,List 这几个类,你会惊奇的发现他们都具备这个方法!那我们就可以大胆的猜测是不是只要实现了这个GetEnumerator()方法就能实现foreach遍历呢;

      这个时候我们在上面的Person类中也实现这个样的一个方法;实现有两种方法

    方法一:直接在末尾加上这个方法

    方法二:实现IEnumerable接口

    public class Person : IEnumerable
        {
            private List<string> listCar = new List<string>();
    
            public int Count
            {
                get
                {
                    return this.listCar.Count;
                }
    
            }
    
            public string this[int index]
            {
                get
                {
                    return listCar[index];
                }
    
                set
                {
                    if (index >= listCar.Count)
                    {
                        listCar.Add(value);
                    }
                    else
                    {
                        listCar[index] = value;
                    }
                }
            }
            public string Name
            {
                get;
                set;
            }
     
    
            #region IEnumerable 成员
    
            //这个方法的作用不是用来遍历的,而是用来获取一个对象
            //这个对象才是用来遍历的。
            public IEnumerator GetEnumerator()
            {
                return new NotImplementedException();
            }
    
            #endregion
        }

    这个时候我们编译一下,发现不编译通过了。那是不是意味着我们就可以用foreach遍历了呢?
    运行下,抛出一个异常;

      public IEnumerator GetEnumerator()
            {
                return new NotImplementedException();
            }

    你会发现这个方法里面什么都没有,肯定是火抛出异常的!
    从这里我们总结下;任何类型,只要想使用foreach来循环遍历,就必须在当前类型中存在: public IEnumerator GetEnumerator()方法,(一般情况我们会通过实现IEnumerable接口,来创建该方法。)

    我们观察可以发现GetEnumerator的返回类型是IEnumerator  ,我们猜测这个方法的作用不是用来遍历的,,而是用来获取一个对象。由这个对象内部来实现遍历

    我们在定义一个名为PersonEnumerator的类,并且实现IEnumerator 接口,这时你会惊奇的发现,里面提供了三个方法Current(),MoveNext(),Reset();这里实现下接口就能实现,就不在粘代码了

    直接把写好的拿上来

     1  //这个类型,的作用就是用来遍历Person中的List集合的。
     2     public class PersonEnumerator : IEnumerator
     3     {
     4         public PersonEnumerator(List<string> _cars)
     5         {
     6             cars = _cars;
     7         }
     8 
     9         //这个字段中存储的就是Person对象中的listCar集合
    10         private List<string> cars;
    11 
    12 
    13         //假设一开始遍历的对象的索引是-1
    14         private int index = -1;
    15 
    16         #region IEnumerator 成员
    17 
    18 
    19         //表示获取当前正在遍历的那个对象
    20         public object Current
    21         {
    22             get
    23             {
    24                 if (index < 0)
    25                 {
    26                     return null;
    27                 }
    28                 return cars[index];
    29             }
    30         }
    31         //让自定义下标index累加
    32         public bool MoveNext()
    33         {
    34             index = index + 1;
    35             if (index >= cars.Count)
    36             {
    37                 return false;
    38             }
    39             else
    40             {
    41                 return true;
    42             }
    43         }
    44 
    45         public void Reset()
    46         {
    47             index = -1;
    48         }
    49 
    50         #endregion
    51     }

    并且修改Person里面的GetEnumerator方法

    1  public IEnumerator GetEnumerator()
    2         {
    3             return new PersonEnumerator(listCar);
    4         }

    这个时候我们在运行遍历下,这个时候已经可以使用foreach遍历了;想看内部怎么调用方法实现的吗?

    1  IEnumerator etor = p.GetEnumerator();
    2             while (etor.MoveNext())
    3             {
    4               string str = etor.Current.ToString();
    5                 Console.WriteLine(str);
    6             }
    7             Console.ReadKey();
  • 相关阅读:
    《数据结构》张明瑞 清华大学 计算机科学与技术专业 大二
    Android studio 快捷键
    android下的样式
    Android照片墙应用实现,再多的图片也不怕崩溃
    菜单
    Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能
    自动文本提示控件
    Android高效加载大图、多图解决方案,有效避免程序OOM
    notification+service实现消息推送
    常见对话框
  • 原文地址:https://www.cnblogs.com/sc0791/p/2648345.html
Copyright © 2011-2022 走看看