全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

总结

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


# c  # foreach  # 枚举  # foreach语句  # 详解C# 枚举高级用法之Description  # C# 实现枚举转列表  # 简述C#枚举高级战术  # 详细了解C# 枚举与位枚举  # 快速学习c# 枚举  # 细说C#中的枚举:转换、标志和属性  # C#如何获取枚举的描述属性详解  # C#中如何为枚举类型添加描述方法【小技巧】  # C#如何利用反射将枚举绑定到下拉框详解  # C#中变量、常量、枚举、预处理器指令知多少  # C# 枚举的使用简介  # 迭代  # 组中  # 这段  # 重写  # 如图  # 所示  # 会把  # 这篇文章  # 谢谢大家  # 装了  # 转换为  # 方法来  # 创建一个  # 就可以  # 有一个  # 类中  # 客户端  # 其中包含  # 实现了  # 从而使 


相关文章: 如何在Mac上搭建Golang开发环境_使用Homebrew安装和管理Go版本  宁波自助建站系统如何快速打造专业企业网站?  c++怎么使用类型萃取type_traits_c++ 模板元编程类型判断【方法】  建站之星手机一键生成:多端自适应+小程序开发快速建站指南  建站之星如何快速更换网站模板?  为什么Go需要go mod文件_Go go mod文件作用说明  如何撰写建站申请书?关键要点有哪些?  制作网站建设的公司有哪些,网站建设比较好的公司都有哪些?  番禺网站制作公司哪家值得合作,番禺图书馆新馆开放了吗?  建站主机选购指南与交易推荐:核心配置解析  定制建站流程解析:需求评估与SEO优化功能开发指南  Swift中switch语句区间和元组模式匹配  极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?  如何获取PHP WAP自助建站系统源码?  如何基于PHP生成高效IDC网络公司建站源码?  Java解压缩zip - 解压缩多个文件或文件夹实例  如何自定义建站之星模板颜色并下载新样式?  学校建站服务器如何选型才能满足性能需求?  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  香港服务器建站指南:免备案优势与SEO优化技巧全解析  ,南京靠谱的征婚网站?  如何在IIS7中新建站点?详细步骤解析  建设网站制作价格,怎样建立自己的公司网站?  文字头像制作网站推荐软件,醒图能自动配文字吗?  如何用y主机助手快速搭建网站?  电影网站制作价格表,那些提供免费电影的网站,他们是怎么盈利的?  建站之家VIP精选网站模板与SEO优化教程整合指南  如何快速辨别茅台真假?关键步骤解析  红河网站制作公司,红河事业单位身份证如何上传?  C#如何序列化对象为XML XmlSerializer用法  如何在Golang中使用encoding/gob序列化对象_存储和传输数据  北京制作网站的公司,北京铁路集团官方网站?  如何通过wdcp面板快速创建网站?  建站之星如何配置系统实现高效建站?  制作充值网站的软件,做人力招聘为什么要自己交端口钱?  如何通过宝塔面板实现本地网站访问?  建站org新手必看:2024最新搭建流程与模板选择技巧  建站之星各版本价格是多少?  清单制作人网站有哪些,近日“兴风作浪的姑奶奶”引起很多人的关注这是什么事情?  微信h5制作网站有哪些,免费微信H5页面制作工具?  宝塔建站无法访问?如何排查配置与端口问题?  ,柠檬视频怎样兑换vip?  网站图片在线制作软件,怎么在图片上做链接?  建站之星后台管理:高效配置与模板优化提升用户体验  公众号网站制作网页,微信公众号怎么制作?  如何正确选择百度移动适配建站域名?  如何通过虚拟机搭建网站?详细步骤解析  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  如何用景安虚拟主机手机版绑定域名建站?  早安海报制作网站推荐大全,企业早安海报怎么每天更换? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。