C#学习之foreach循环原理

 

C#学习之foreach循环原理

结构篇:

foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但不应用于更改集合内容以避免产生不可预知的副作用。此语句的形式如下: 

foreach (type identifier in expression) statement 

其中: 

type 
identifier 的类型。 
identifier 
表示集合元素的迭代变量。如果迭代变量为值类型,则无法修改的只读变量也是有效的。 
expression 
对象集合或数组表达式。集合元素的类型必须可以转换为 identifier 类型。请不要使用计算为 null 的表达式。 
而应计算为实现 IEnumerable 的类型或声明 GetEnumerator 方法的类型。在后一种情况中,GetEnumerator 应该要么返回实现 IEnumerator 的类型,要么声明 IEnumerator 中定义的所有方法。 

statement 
要执行的嵌入语句。

原理篇:
在foreach循环中,迭代集合collectionObject的过程如下:
(1)调用collectionObject.GetEnumerator(),返回一个IEnumerator引用。这个方法可以通过IEnumerable接口的实现代码来获得。但这是可选的。
(2)调用返回的IEnumerator接口的MoveNext()方法。
(3)如果MoveNext()方法返回true,就使用IEnumerator接口的Current属性获取对象的一个引用,用于foreach循环。
(4)重复前面两步,直到MoveNext()方法返回false为止,此时循环停止。

 

[csharp] view plaincopy
  1. //替代foreach实现:  
  2. foreach (XXX a in b){   
  3. ...   
  4. }   
  5.   
  6. //等同于  
  7. XXX a;  
  8. IEnumerator ie = (IEnumable)b.GetEnumerator();   
  9. while (ie.MoveNext) {   
  10. a = (XXX)ie.Current;   
  11. ...  
  12. }  

 

具体示例:

 

[csharp] view plaincopy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Collections;  
  6.   
  7. namespace _07foreach循环遍历原理  
  8. {  
  9.     class Program  
  10.     {  
  11.         //foreach循环中的Var关键字  
  12.         //var是一个”类型推断“,在程序编译的时候就已经替换成了对应的数据类型。  
  13.         //所以说var是一个强类型(在编译的时候已经可以确定数据类型了。),而不是弱类型。  
  14.         static void Main(string[] args)  
  15.         {  
  16.             #region 示例练习  
  17.             Console.WriteLine("=============1===========");  
  18.             ArrayList list1 = new ArrayList() { 20, 3, 49, 39, 48 };  
  19.             foreach (var item in list1)  
  20.             {  
  21.                 Console.WriteLine(item);  
  22.             }  
  23.   
  24.             Console.WriteLine("=============2===========");  
  25.             string[] names = { "a""b""c""d" };  
  26.             foreach (var item in names)//var可以用 string代替  
  27.             {  
  28.                 Console.WriteLine(item);  
  29.             }  
  30.   
  31.             Console.WriteLine("=============3===========");  
  32.             List<string> list2 = new List<string>() { "乔丹""可比""詹姆斯" };  
  33.             foreach (var item in list2)//var可以用 string代替  
  34.             {  
  35.                 Console.WriteLine(item);  
  36.             }  
  37.             #endregion  
  38.  
  39.             #region foreach原理初探  
  40.             //任何类型,只要想使用foreach来循环遍历,就必须在当前类型中存在:  
  41.             //public IEnumerator GetEnumerator()方法,(一般情况我们会通过实现IEnumerable接口,来创建该方法。)  
  42.             Console.WriteLine("=============4===========");  
  43.             Person p = new Person();  
  44.             p[0] = "BMW";  
  45.             p[1] = "凯迪拉克";  
  46.             p[2] = "阿斯顿马丁";  
  47.             //for循环遍历输出  
  48.             Console.WriteLine("=======for循环遍历输出======");  
  49.             for (int i = 0; i < p.Count; i++)  
  50.             {  
  51.                 Console.WriteLine(p[i]);  
  52.             }  
  53.             //foreach循环遍历输出  
  54.             Console.WriteLine("=======foreach循环遍历输出======");  
  55.             foreach (var item in p)  
  56.             {  
  57.                 Console.WriteLine(item);  
  58.             }  
  59.             //foreach循环原理遍历输出  
  60.             Console.WriteLine("=======foreach循环原理遍历输出======");  
  61.             IEnumerator etor = p.GetEnumerator();  
  62.             while (etor.MoveNext())  
  63.             {  
  64.                 string str = etor.Current.ToString();  
  65.                 Console.WriteLine(str);  
  66.             }  
  67.             #endregion  
  68.   
  69.             Console.ReadKey();  
  70.         }  
  71.     }  
  72.   
  73.     public class Person :IEnumerable  
  74.     {  
  75.         private List<string> listCar = new List<string>();  
  76.   
  77.         public int Count   
  78.         {  
  79.             get   
  80.             {  
  81.                 return this.listCar.Count;  
  82.             }  
  83.         }  
  84.   
  85.         public string this[int index]  
  86.         {  
  87.             get  
  88.             {  
  89.                 return listCar[index];  
  90.             }  
  91.             set   
  92.             {  
  93.                 if (index >= listCar.Count)  
  94.                 {  
  95.                     listCar.Add(value);  
  96.                 }  
  97.                 else   
  98.                 {  
  99.                     listCar[index] = value;  
  100.                 }  
  101.             }  
  102.         }  
  103.   
  104.         public string Name  
  105.         {  
  106.             get;  
  107.             set;  
  108.         }  
  109.   
  110.         public int Age  
  111.         {  
  112.             get;  
  113.             set;  
  114.         }  
  115.   
  116.         public string Email  
  117.         {  
  118.             get;  
  119.             set;  
  120.         }  
  121.   
  122.         //这个方法的作用不是用来遍历的,而是用来获取 一个对象  
  123.         //这个对象才是用来遍历的  
  124.         public IEnumerator GetEnumerator()  
  125.         {  
  126.             return new PersonEnumerator(listCar);  
  127.         }  
  128.     }  
  129.   
  130.     /// <summary>  
  131.     /// 这个类型的作用就是 用来遍历Person中的List集合的  
  132.     /// </summary>  
  133.     public class PersonEnumerator : IEnumerator  
  134.     {  
  135.         public PersonEnumerator(List<string> _cars)  
  136.         {  
  137.             this.cars = _cars;  
  138.         }  
  139.   
  140.         //这个字段中存储的就是Person对象中的listCar集合  
  141.         private List<string> cars;  
  142.   
  143.         //假设一开始遍历的对象的索引是-1  
  144.         private int index = -1;  
  145.   
  146.         //表示获取当前正在遍历的那个对象  
  147.         public object Current  
  148.         {  
  149.             get   
  150.             {  
  151.                 if (index<0)  
  152.                 {  
  153.                     return null;  
  154.                 }  
  155.                 return cars[index];  
  156.             }  
  157.         }  
  158.   
  159.         //让自定义下标index累加  
  160.         public bool MoveNext()  
  161.         {  
  162.             index = index + 1;  
  163.             if (index>=cars.Count)  
  164.             {  
  165.                 return false;  
  166.             }  
  167.             else  
  168.             {  
  169.                 return true;  
  170.             }  
  171.         }  
  172.   
  173.         //重置  
  174.         public void Reset()  
  175.         {  
  176. ASP.Net+Android+IOS开发.Net培训、期待与您交流! important; padding-right: 3px !important; border-top-style: none; color: #5c5c5c; padding-top: 0px !important;">            index = -1;  
  177.         }  
  178.     }  
  179. }  

输出结果如下:

可以根据下图进行深入理解foreach执行原理:

 

原文地址:https://www.cnblogs.com/chenanzixue/p/3445833.html