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

 更新时间:2020年6月25日 11:19  点击:2295

前言

在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();
    }
   }
  }

总结

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

[!--infotagslink--]

相关文章

  • C#实现简单的登录界面

    我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
  • 浅谈C# 字段和属性

    这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
  • C#中截取字符串的的基本方法详解

    这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
  • C#实现简单的Http请求实例

    这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • C#中new的几种用法详解

    本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
  • 使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)

    这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
  • C#从数据库读取图片并保存的两种方法

    这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • C#绘制曲线图的方法

    这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • c#自带缓存使用方法 c#移除清理缓存

    这篇文章主要介绍了c#自带缓存使用方法,包括获取数据缓存、设置数据缓存、移除指定数据缓存等方法,需要的朋友可以参考下...2020-06-25
  • c#中(&&,||)与(&,|)的区别详解

    这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • 经典实例讲解C#递归算法

    这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
  • C#学习笔记- 随机函数Random()的用法详解

    下面小编就为大家带来一篇C#学习笔记- 随机函数Random()的用法详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#中list用法实例

    这篇文章主要介绍了C#中list用法,结合实例形式分析了C#中list排序、运算、转换等常见操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25