好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C#中foreach实现原理详解

本文主要记录我在学习C#中foreach遍历原理的心得体会。

对集合中的要素进行遍历是所有编码中经常涉及到的操作,因此大部分编程语言都把此过程写进了语法中,比如C#中的foreach。经常会看到下面的遍历代码:

?

var lstStr = new List< string > { "a" , "b" };

    foreach (var str in lstStr)

       {

         Console.WriteLine(str);

       }

实际此代码的执行过程:

?

var lstStr = new List<string> { "a" , "b" };

    IEnumerator<string> enumeratorLst = lstStr.GetEnumerator();

    while (enumeratorLst.MoveNext())

       {

         Console.WriteLine(enumeratorLst.Current);

       }

会发现有GetEnumerator()方法和IEnumerator<string>类型,这就涉及到可枚举类型和枚举器的概念。

为了方便理解,以下为非泛型示例:

?

// 摘要:

//   公开枚举器,该枚举器支持在非泛型集合上进行简单迭代。

   public interface IEnumerable

   {

     // 摘要:

     //   返回一个循环访问集合的枚举器。

     //

     // 返回结果:

     //   可用于循环访问集合的 System.Collections.IEnumerator 对象。

     IEnumerator GetEnumerator();

   }

实现了此接口的类称为可枚举类型,是可以用foreach进行遍历的标志。

方法GetEnumerator()的返回值是枚举器,可以理解为游标。

?

// 摘要:

//   支持对非泛型集合的简单迭代。

   public interface IEnumerator

   {

     // 摘要:

     //   获取集合中的当前元素。

     //

     // 返回结果:

     //   集合中的当前元素。

     //

     // 异常:

     //  System.InvalidOperationException:

     //   枚举数定位在该集合的第一个元素之前或最后一个元素之后。

     object Current { get; }

 

     // 摘要:

     //   将枚举数推进到集合的下一个元素。

     //

     // 返回结果:

     //   如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false。

     //

     // 异常:

     //  System.InvalidOperationException:

     //   在创建了枚举数后集合被修改了。

     bool MoveNext();

     //

     // 摘要:

     //   将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。

     //

     // 异常:

     //  System.InvalidOperationException:

     //   在创建了枚举数后集合被修改了。

     void Reset();

   }

以下是自定义一个迭代器的示例(https://msdn.microsoft测试数据/en-us/library/system.collections.ienumerator.aspx):

 

?

using System;

using System.Collections;

 

// Simple business object.

public class Person

{

   public Person( string fName, string lName)

   {

     this .firstName = fName;

     this .lastName = lName;

   }

 

   public string firstName;

   public string lastName;

}

 

// Collection of Person objects. This class

// implements IEnumerable so that it can be used

// with ForEach syntax.

public class People : IEnumerable

{

   private Person[] _people;

   public People(Person[] pArray)

   {

     _people = new Person[pArray.Length];

 

     for ( int i = 0; i < pArray.Length; i++)

     {

       _people[i] = pArray[i];

     }

   }

 

// Implementation for the GetEnumerator method.

   IEnumerator IEnumerable.GetEnumerator()

   {

     return (IEnumerator) GetEnumerator();

   }

 

   public PeopleEnum GetEnumerator()

   {

     return new PeopleEnum(_people);

   }

}

 

// When you implement IEnumerable, you must also implement IEnumerator.

public class PeopleEnum : IEnumerator

{

   public Person[] _people;

 

   // Enumerators are positioned before the first element

   // until the first MoveNext() call.

   int position = -1;

 

   public PeopleEnum(Person[] list)

   {

     _people = list;

   }

 

   public bool MoveNext()

   {

     position++;

     return (position < _people.Length);

   }

 

   public void Reset()

   {

     position = -1;

   }

 

   object IEnumerator.Current

   {

     get

     {

       return Current;

     }

   }

 

   public Person Current

   {

     get

     {

       try

       {

         return _people[position];

       }

       catch (IndexOutOfRangeException)

       {

         throw new InvalidOperationException();

       }

     }

   }

}

 

class App

{

   static void Main()

   {

     Person[] peopleArray = new Person[3]

     {

       new Person( "John" , "Smith" ),

       new Person( "Jim" , "Johnson" ),

       new Person( "Sue" , "Rabon" ),

     };

 

     People peopleList = new People(peopleArray);

     foreach (Person p in peopleList)

       Console.WriteLine(p.firstName + " " + p.lastName);

 

   }

}

 

/* This code produces output similar to the following:

  *

  * John Smith

  * Jim Johnson

  * Sue Rabon

  *

  */

在有了yield这个关键字以后,我们可以通过这样的方式来创建枚举器:

?

using System;

using System.Collections;

 

// Simple business object.

public class Person

{

   public Person( string fName, string lName)

   {

     this .firstName = fName;

     this .lastName = lName;

   }

 

   public string firstName;

   public string lastName;

}

 

// Collection of Person objects. This class

// implements IEnumerable so that it can be used

// with ForEach syntax.

public class People : IEnumerable

{

   private Person[] _people;

 

   public People(Person[] pArray)

   {

     _people = new Person[pArray.Length];

 

     for ( int i = 0; i < pArray.Length; i++)

     {

       _people[i] = pArray[i];

     }

   }

 

   // Implementation for the GetEnumerator method.

   IEnumerator IEnumerable.GetEnumerator()

   {

     for ( int i = 0; i < _people.Length; i++)

     {

       yield return _people[i];

     }

   }

 

}

 

 

class App

{

   static void Main()

   {

     Person[] peopleArray = new Person[3]

     {

       new Person( "John" , "Smith" ),

       new Person( "Jim" , "Johnson" ),

       new Person( "Sue" , "Rabon" ),

     };

 

     People peopleList = new People(peopleArray);

     foreach (Person p in peopleList)

       Console.WriteLine(p.firstName + " " + p.lastName);

   }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://HdhCmsTestcnblogs测试数据/alongdada/archive/2017/09/26/7598119.html

dy("nrwz");

查看更多关于C#中foreach实现原理详解的详细内容...

  阅读:41次