好得很程序员自学网

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

C#从foreach语句中枚举元素看数组详解

前言

在foreach语句中使用枚举,可以迭代数组或集合中的元素,且无须知道集合中的元素的个数。如图显示了调用foreach方法的客户端和集合之间的关系。数组或集合实现带 GetEnumerator() 方法的IEnumerable接口。 GetEnumerator() 方法返回一个实现lEnumerable接口的枚举,接着foreach语句就可以使用IEnumerable接口迭代集合了。

GetEnumerator() 方法用IEnumerable接口定义,foreach语句并不真的需要在集合类中实现这个接口。有一个名为 GetEnumerator() 的方法它返回实现了IEnumerator接口的对象就足够了。

先定义一个Person类,这个类有自动实现的属性Firstname和Lastname,以及从Object类重写ToString方法和继承泛型接口IEquatable以比较两个对象是否相等,实现泛型接口IComparer以比较两个对象用来排序。

?

public class Person : IEquatable<Person>,IComparable<Person>

  {

   public int Id { get ; private set ; }

   public string FirstName { get ; set ; }

   public string LastName { get ; set ; }

 

   public override string ToString()

   {

    return String.Format( "{0}, {1} {2}" , Id, FirstName, LastName);

   }

 

   public bool Equals(Person other)

   {

    if (other == null )

     return base .Equals(other);

 

    return this .FirstName == other.FirstName && this .LastName == other.LastName;

   }

 

   public int CompareTo(Person other)

   {

    if (other == null ) throw new ArgumentNullException( "other" );

 

    int result = this .LastName.CompareTo(other.LastName);

    if (result == 0)

    {

     result = this .FirstName.CompareTo(other.FirstName);

    }

 

    return result;

   }

 

  }

创建一个三个元素的person数组,现对数组进行排序在用foreach循环访问数组中的元素并输出

?

Person[] persons = {

    new Person { FirstName = "Simen03" , LastName = "Go" },

    new Person { FirstName = "Simen02" , LastName = "Go" },

    new Person { FirstName = "Simen01" , LastName = "Go" }

   };

   Array.Sort(persons);

   foreach (var person in persons)

    Console.WriteLine(person);

分析 foreach (var person in persons)Console.WriteLine(person); 这段代码IL代码

?

// loop start (head: IL_009b)

    IL_008a: ldloc.2

    IL_008b: ldloc.3

    IL_008c: ldelem. ref

    IL_008d: stloc.s person

    IL_008f: ldloc.s person

    IL_0091: call void [mscorlib]System.Console::WriteLine( object )

    IL_0096: nop

    IL_0097: ldloc.3

    IL_0098: ldc.i4.1

    IL_0099: add

    IL_009a: stloc.3

 

    IL_009b: ldloc.3

    IL_009c: ldloc.2

    IL_009d: ldlen

    IL_009e: conv.i4

    IL_009f: blt.s IL_008a

   // end loop

C#的foreach语句不会解析为IL代码中的foreach语句,C#编译器会把foreach语句转换为IEnumerable接口的方法和属性,foreach语句使用IEnumerator接口的方法和属性,迭代数组中的所有元素,为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的 MoveNext() 方法移动到数组的下一个元素上,如果有这个元素该方法就返回true否则返回false,这个接口的泛型版本IEnumerator派生自接口IDisposable,因此定义了 Dispose() 方法来清理枚举器占用的资源,使用foreach语句会解析为下面的代码段

?

IEnumerator enumerator = persons.GetEnumerator();

   while (enumerator.MoveNext())

   {

    var person = enumerator.Current;

    Console.WriteLine(person);

   }

为了方便的创建枚举器,C#添加了yield语句,yield return 语句返回集合的一个元素,并移动到下一个元素,yield break 可停止迭代。使用迭代块,编译器会生成一个yield类型,其中包含一个状态机,如下代码段所示。yield 类型实现IEnumerator和IDisposable接口的属性和方法。在下面的例子中,可以把yield类型看作内部类Enumerator.外部类的 GetEnumerator() 方法实例化并返回一个新的yield类型。在yield类型中,变量state定义了迭代的当前位置,每次调用 MoveNext() 时,当前位置都会改变, MoveNext() 封装了迭代代码,并设置了current变量的值,从而使Current属性根据位置返回一个对象。

?

static void Main( string [] args)

  {

   var helloCollection = new HelloCollection();

   foreach ( string s in helloCollection)

   {

    Console.WriteLine(s);

   }

  }

 

  public class HelloCollection

  {

   public IEnumerator< string > GetEnumerator()

   {

    yield return "Hello" ;

    yield return "World" ;

   }

  }

  public class HelloCollectionOther

  {

   public IEnumerator GetEnumertor()

   {

    return new Enumerator(0);

   }

   public class Enumerator : IEnumerator< string >, IEnumerator, IDisposable

   {

    private int state;

    private string current;

    public Enumerator( int state)

    {

     this .state = state;

    }

 

    public string Current => throw new NotImplementedException();

 

    object IEnumerator.Current

    {

     get { return current; }

    }

 

    public void Dispose()

    {

     throw new NotImplementedException();

    }

 

    public bool MoveNext()

    {

     switch (state)

     {

      case 0:current = "hello" ;

       state = 1;

       return true ;

      case 1:current = "world" ;

       state = 2;

       return true ;

      case 2:

       break ;

     }

     return false ;

    }

 

    public void Reset()

    {

     throw new NotImplementedException();

    }

   }

  }

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:http://www.cnblogs.com/simen-tan/p/6816750.html

dy("nrwz");

查看更多关于C#从foreach语句中枚举元素看数组详解的详细内容...

  阅读:40次