foreach适合在什么情况下使用+foreach的内部原理剖析

先看下面这段代码;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();

 

 

 

 

posted @ 2012-08-20 23:44  Carl --卡尔  阅读(1984)  评论(0编辑  收藏  举报