浅析foreach原理
在日常开发工作中,我们发现很多对象都能通过foreach来遍历,比如HashTable、Dictionary、数组等数据类型。那为何这些对象能通过foreach来遍历呢?如果写一个普通的Person类,也希望它能通过foreach来遍历应该怎么做?通过查看,发现HashTable、Dictionary、数组等数据类型都实现了一个叫IEnumerable(或其泛型版本)的接口。现在也来尝试下,让Person类实现这个接口(其实实不实现IEnumerable接口不是必须的,只要类型中有public IEnumerator GetEnumerator()这个方法即可):
1 class Person:IEnumerable 2 { 3 public string[] _Name = new string[] { "sk", "jk", "yzk","wcw","ml" }; 4 public string Name { get; set; } 5 public int Age { get; set; } 6 7 public IEnumerator GetEnumerator() 8 { 9 return new PersonEnumerator(_Name); 10 } 11 }
可以看到GetEnumerator()方法需要一个返回值类型为实现了IEnumerator的类型,那就写个类,让其实现IEnumerator接口:
1 class PersonEnumerator:IEnumerator 2 { 3 public PersonEnumerator(string[] name) 4 { 5 this._names = name; 6 } 7 8 public string[] _names { get; set; } 9 public int Index = -1; 10 11 public object Current 12 { 13 get { return _names[Index]; } 14 } 15 16 public bool MoveNext() 17 { 18 Index++; 19 if (Index>=_names.Length) 20 { 21 return false; 22 } 23 else 24 { 25 return true; 26 } 27 } 28 29 public void Reset() 30 { 31 Index = -1; 32 } 33 }
此时再运行程序,就发现Person类可以遍历了。运行结果如下:
总结,一种类型要想通过foreach遍历,其内部必须有public IEnumerator GetEnumerator()这个方法,而通常的做法是让类型实现IEnumerable接口。
上面的代码还有一个问题,就是Person对象通过foreach遍历时,var并没有推断出是string类型而是object类型,这是因为Current就是object导致的,解决的方案就是泛型,看下面的代码:
1 class Person 2 { 3 public string Name { get; set; } 4 public int Age { get; set; } 5 public string[] _Name = new string[] { "zxh", "jk", "ml", "wcw", "sk", "yzk","lmn" }; 6 7 public IEnumerator<string> GetEnumerator() 8 { 9 return new MyClass<string>(_Name); 10 } 11 } 12 13 class MyClass<T>:IEnumerator<T> 14 { 15 public MyClass(T[] _Names) 16 { 17 this.names = _Names; 18 } 19 public T Current 20 { 21 get { return names[Index]; } 22 } 23 24 private T[] names { get; set; } 25 private int Index = -1; 26 27 public void Dispose() 28 { 29 //throw new NotImplementedException(); 30 } 31 32 object IEnumerator.Current 33 { 34 get { throw new NotImplementedException(); } 35 } 36 37 public bool MoveNext() 38 { 39 Index++; 40 if (Index>=names.Length) 41 { 42 return false; 43 } 44 else 45 { 46 return true; 47 } 48 } 49 50 public void Reset() 51 { 52 Index = -1; 53 } 54 }
使用的方法如下:
1 Person p1 = new Person(); 2 foreach (var item in p1) 3 { 4 Console.WriteLine(item); 5 }
可以看到var已经被推断成string.
下面看一下,自己写的foreach遍历,还是那个Person类(必须有IEnumerator GetEnumerator()这个方法):
把foreach遍历换成下面的代码:
1 Person p1 = new Person(); 2 IEnumerator enumer = p1.GetEnumerator(); 3 while (enumer.MoveNext()) 4 { 5 Console.WriteLine(enumer.Current); 6 }
上面的代码也是能够正常执行的。
扩展:
1 List<string> strLst = new List<string>(); //查看定义得知,其实现了IEnumerable<T>和IEnumerable2个接口 2 strLst.AddRange(new string[] { "sk", "jk", "yzk" }); 3 IEnumerator enumer = strLst.GetEnumerator(); 4 while (enumer.MoveNext()) 5 { 6 Console.WriteLine(enumer.Current); 7 }
一般没人会这么写,遍历一个对象还是直接写foreach。这只不过是其原理。
1 Dictionary<int, char> dic = new Dictionary<int, char>(); 2 dic.Add(1, '壹'); 3 dic.Add(2, '贰'); 4 dic.Add(3, '叁'); 5 dic.Add(4, '肆'); 6 dic.Add(5, '伍'); 7 dic.Add(6, '陆'); 8 dic.Add(7,'柒'); 9 dic.Add(8,'扒'); 10 dic.Add(9,'玖'); 11 12 IEnumerator iEnumer = dic.GetEnumerator(); 13 while (iEnumer.MoveNext()) 14 { 15 KeyValuePair<int, char> item = (KeyValuePair<int, char>)iEnumer.Current; 16 Console.WriteLine(item.Key+" "+item.Value); 17 }
转载于:https://www.cnblogs.com/chens2865/p/3860619.html
浅析foreach原理相关推荐
- 浅析bootstrap原理及优缺点
网格系统的实现原理,是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统 网格系统的实现原理,是通过定义容器 ...
- 手把手带你学会Odoo OWL组件开发(5):浅析OWL原理
[本系列内容直达:] 手把手带你学习Odoo OWL组件开发(1):认识 OWL 手把手带你学会Odoo OWL组件开发(2):OWL的使用 手把手带你学会Odoo OWL组件开发(3):核心内容指南 ...
- java foreach 原理_一不小心就让Java开发者踩坑的failfast是个什么鬼?
1 什么是fail-fast 首先我们看下维基百科中关于fail-fast的解释: 在系统设计中,快速失效系统一种可以立即报告任何可能表明故障的情况的系统.快速失效系统通常设计用于停止正常操作,而不是 ...
- 浅析Kerberos原理,及其应用和管理
文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/5269739.html 转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...
- 浅析ajax原理与用法
1 ajax原理 Ajax(Asynchronous JavaScript and XML (异步的JavaScript和XML)),是一种快速创建 动态网页的技术,目的是显示动态局部刷新.通过XML ...
- TUN/TAP设备浅析(一) -- 原理浅析
TUN/TAP设备浅析 TUN设备 TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便地模拟网络行为.TUN 模拟的是一个三层设备,也就是说,通过它可以处理来自网络层的数据,更通俗一点的说,通过 ...
- 浅析ElasticSearch原理
女主宣言 最近女主在项目中使用到ElasticSearch来做索引.但是对ElasticSearch的一些原理还是比较模糊,所以就梳理了一下ElasticSearch的基本原理,分享给大家. PS:丰 ...
- 浅析SSRF原理及利用方式
原文链接:https://www.anquanke.com/post/id/145519 漏洞简介 SSRF(Server-side Request Forge, 服务端请求伪造) 通常用于控制web ...
- 浅析Promise原理
Promise原型对象 在浏览器控制台输入如下代码,可以看到Promise原型对象信息. var p = new Promise(()=>{}); console.log(p) Promise原 ...
最新文章
- WPF加载相对路径的图片的解决方法
- Spring 注解之@RestController与@Controller的区别
- 搜狗手机助手联合腾讯御安全 共建APP安全生态环境
- 10_史上最全的Markdown使用教程(没有之一)(20190115)
- ThreadLocal 内存泄露的实例分析
- Ubuntu 首次给root用户设置密码
- U(优)盘安装FreeBSD-9.0+GNOME_lite桌面
- vue实现的tabs标签组件
- linux消息队列的内核限制
- Java新特性之Nashorn的实例详解
- webrtc java api_java – 使用WebSockets实现WebRTC信令
- webstorm 高效开发 (html)
- 技巧8——linux假死现象要知道
- 怎么利用企业微信营销 企业微信如何营销 企业微信如何维护好友 企业微信如何开通
- 工具说明书 - FTDI芯片的USB转UART串口线
- 为什么您没有得到最好的承包商,您将如何做(第2部分)
- 如何选择字体(font-family)
- 康沣生物通过港交所聆讯:持续亏损、现金流紧张,李克俭为董事长
- 哈夫曼树的构建及哈夫曼树编码
- Unity特效学习笔记——子弹
热门文章
- freemarker如何判空容错
- sql 纵向求和_sql 行列转换 求和平均值等
- 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列
- 无线短距通信技术标准:WIFI,蓝牙,ZigBee
- c语言编译asn1文件,使用 asn1.c 开源编译工具生成 S1AP R15消息编解码C文件
- electronjs设置宽度_electronjs 入门_2019年2月14日
- SQL Server高级查询之子查询(子查询非典型应用)
- SSM之Mybatis框架
- [leetcode]241. 为运算表达式设计优先级
- bzoj 3396: [Usaco2009 Jan]Total flow 水流(最大流)