浅析foreach原理
在日常开发工作中,我们发现很多对象都能通过foreach来遍历,比如HashTable、Dictionary、数组等数据类型。那为何这些对象能通过foreach来遍历呢?如果写一个普通的Person类,也希望它能通过foreach来遍历应该怎么做?通过查看,发现HashTable、Dictionary、数组等数据类型都实现了一个叫IEnumerable(或其泛型版本)的接口。现在也来尝试下,让Person类实现这个接口(其实实不实现IEnumerable接口不是必须的,只要类型中有public IEnumerator GetEnumerator()这个方法即可):
class Person:IEnumerable
{
public string[] _Name = new string[] { "sk", "jk", "yzk","wcw","ml" };
public string Name { get; set; }
public int Age { get; set; } public IEnumerator GetEnumerator()
{
return new PersonEnumerator(_Name);
}
}
可以看到GetEnumerator()方法需要一个返回值类型为实现了IEnumerator的类型,那就写个类,让其实现IEnumerator接口:
class PersonEnumerator:IEnumerator
{
public PersonEnumerator(string[] name)
{
this._names = name;
} public string[] _names { get; set; }
public int Index = -; public object Current
{
get { return _names[Index]; }
} public bool MoveNext()
{
Index++;
if (Index>=_names.Length)
{
return false;
}
else
{
return true;
}
} public void Reset()
{
Index = -;
}
}
此时再运行程序,就发现Person类可以遍历了。运行结果如下:
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAABbCAIAAABVkfp3AAABSUlEQVRoge3WQRbCIAxFUfa/KlbhZpw4qiJJ2l8hIbX/zao9hytgaXnmq6wGKH1MjzR9mUqSaMK6qqluJTK9WTRtptpkmdx9rWln4PdlxISp8yRvs+YvwtQKpEn9yteErF0EC9nj3SfRphTRhEUTFk1Ylkk+kJa9F6gmebnG1LXYtHO8BPnOrl30e8GhKWgFLz9P6le+JmvgbtVSmKJD3jMXm1JEExZNWCMmr3/o4Dzd1aQ+yqtINU3zgSYVId0TQKDJAhWnswg0WaNGzFPRfrpcL2mayULe6aqo+zzCNHl/jJhcNuygaaWjjSYsmrBowspukueaeryoN8hLX5N1qIWaOoo1mHX/v5ssB7Je00CgqRh7PMiUIpqwaMKiCQs0Wc+nlaZWdntTFWUxFfucp4mmX0xScLj9vUyOw5yKJiyasGjCogmLJqgXyORSIrl5R8IAAAAASUVORK5CYII=" alt="" />
总结,一种类型要想通过foreach遍历,其内部必须有public IEnumerator GetEnumerator()这个方法,而通常的做法是让类型实现IEnumerable接口。
上面的代码还有一个问题,就是Person对象通过foreach遍历时,var并没有推断出是string类型而是object类型,这是因为Current就是object导致的,解决的方案就是泛型,看下面的代码:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string[] _Name = new string[] { "zxh", "jk", "ml", "wcw", "sk", "yzk","lmn" }; public IEnumerator<string> GetEnumerator()
{
return new MyClass<string>(_Name);
}
} class MyClass<T>:IEnumerator<T>
{
public MyClass(T[] _Names)
{
this.names = _Names;
}
public T Current
{
get { return names[Index]; }
} private T[] names { get; set; }
private int Index = -; public void Dispose()
{
//throw new NotImplementedException();
} object IEnumerator.Current
{
get { throw new NotImplementedException(); }
} public bool MoveNext()
{
Index++;
if (Index>=names.Length)
{
return false;
}
else
{
return true;
}
} public void Reset()
{
Index = -;
}
}
使用的方法如下:
Person p1 = new Person();
foreach (var item in p1)
{
Console.WriteLine(item);
}
可以看到var已经被推断成string.
下面看一下,自己写的foreach遍历,还是那个Person类(必须有IEnumerator GetEnumerator()这个方法):
把foreach遍历换成下面的代码:
Person p1 = new Person();
IEnumerator enumer = p1.GetEnumerator();
while (enumer.MoveNext())
{
Console.WriteLine(enumer.Current);
}
上面的代码也是能够正常执行的。
扩展:
List<string> strLst = new List<string>(); //查看定义得知,其实现了IEnumerable<T>和IEnumerable2个接口
strLst.AddRange(new string[] { "sk", "jk", "yzk" });
IEnumerator enumer = strLst.GetEnumerator();
while (enumer.MoveNext())
{
Console.WriteLine(enumer.Current);
}
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAA2CAIAAAA+tZzsAAAA3ElEQVRYhe3VSRKFMAgE0Nz/VDnFv4wbV1pWGvgSGxyK3jmUDzDGttya9iz+lxuBb5kp/hV833IPv1fwdb4fovGcUpA3jP2QNgaje7xZmwqZP2LIG/UR+DPDp1VwfukNZwL5vBRffPHI44ee8ccTeTwM54fk8ca+yyxlbviBf7y/PPMVvK978RKN14xh7Nl8SMTh85eYi89L8cXP85e+EUr33+LFja9DRN5XiovX2h1KDOles9uVTdrFawC5e7EhHDjy7grslY/P1cri8zPv0hvk59cRhQ8ni38GvwIupIVjdGbDCgAAAABJRU5ErkJggg==" alt="" />
一般没人会这么写,遍历一个对象还是直接写foreach。这只不过是其原理。
Dictionary<int, char> dic = new Dictionary<int, char>();
dic.Add(, '壹');
dic.Add(, '贰');
dic.Add(, '叁');
dic.Add(, '肆');
dic.Add(, '伍');
dic.Add(, '陆');
dic.Add(,'柒');
dic.Add(,'扒');
dic.Add(,'玖'); IEnumerator iEnumer = dic.GetEnumerator();
while (iEnumer.MoveNext())
{
KeyValuePair<int, char> item = (KeyValuePair<int, char>)iEnumer.Current;
Console.WriteLine(item.Key+" "+item.Value);
}
浅析foreach原理的更多相关文章
- Foreach原理
本质:实现了一个IEnumerable接口, 01.为什么数组和集合可以使用foreach遍历? 解析:因为数组和集合都实现了IEnumerable接口,该接口中只有一个方法,GetEnumerato ...
- .net学习之集合、foreach原理、Hashtable、Path类、File类、Directory类、文件流FileStream类、压缩流GZipStream、拷贝大文件、序列化和反序列化
1.集合(1)ArrayList内部存储数据的是一个object数组,创建这个类的对象的时候,这个对象里的数组的长度为0(2)调用Add方法加元素的时候,如果第一次增加元神,就会将数组的长度变为4往里 ...
- 浅析bootstrap原理及优缺点
网格系统的实现原理,是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统 网格系统的实现原理,是通过定义 ...
- Array.forEach原理,仿造一个类似功能
Array.forEach原理,仿造一个类似功能 array.forEach // 设一个arr数组 let arr = [12,45,78,165,68,124]; let sum = 0; // ...
- 浅析WebSocket 原理
浅析WebSocket 原理 长恨此身非我有,何时忘却营营. 简介:先简单了解下WebSocket 原理,日后的使用中再进一步深入研究~ 一.什么是WebSocket WebSocket 是HTML5 ...
- 浅析Kerberos原理,及其应用和管理
文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/5269739.html 转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...
- C#学习笔记:foreach原理
这篇随笔是对上一篇随笔C#关键字:yield的扩展. 关于foreach 首先,对于 foreach ,大家应该都非常熟悉,这里就简单的描述下. foreach 语句用于对实现 System.Col ...
- C#foreach原理
本文主要记录我在学习C#中foreach遍历原理的心得体会. 对集合中的要素进行遍历是所有编码中经常涉及到的操作,因此大部分编程语言都把此过程写进了语法中,比如C#中的foreach.经常会看到下面的 ...
- Foreach 原理
public class Person { private string[] friends = { "asf", "ewrqwe", "ddd&qu ...
随机推荐
- Android实例-使用电话拨号器在移动设备上(官方)(XE8+小米2)
源文地址: http://docwiki.embarcadero.com/RADStudio/XE5/en/Mobile_Tutorial:_Using_the_Phone_Dialer_on_Mob ...
- like用法
SQL:btitle like '%"+keyword+"%' 存储过程:keyword like ''%'+@keyword+'%'' 直接查找:name like '%wang ...
- 经验之巧妙的应用Map
后台: @RequestMapping("/cmci/v_divide_check_add.do") public String toDivideCheckAdd(HttpS ...
- Java任务调度
最近项目要用到任务调度的相关知识,昨天信心满满的去官网学习,结果被坑个半死,我用的最新版的quartz,文档里说是兼容所有版本,但是代码连编译都报错,无奈只好从网上找资料,摸着石头过河总算有点眉目,在 ...
- 委托学习续:Action、Func和Predicate
我们先看一个上一章的委托的例子: using System; using System.Collections.Generic; using System.Linq; using System.Tex ...
- [原创]Android秒杀倒计时自定义TextView
自定义TextView控件TimeTextView代码: import android.content.Context; import android.content.res.TypedArray; ...
- 从零开始学android开发-查看sqlite数据库
C:\Users\Administrator>cd E:\ProSoft\adt-bundle-windows-x86-20140321\sdk\platform-tools
- 什么是IDOC,以及IDOC的步骤
创建IDOC: 第一步:WE31 创建IDOC所包含的字段. 第二步:WE30 创建IDOC 把Segment分配给IDOC 第三步:WE81 创建信息类型 第四步:WE82 把 ...
- SpringMVC+Spring3+hibernate4 开发环境搭建以及一个开发实例教程
刚刚接触了SpringMVC这个框架,因此有必要把它拿过来同hibernate.Spring框架进行集成和开发一个实例,在真正企业从头开发的项目中往往一个稳定的开发环境至关重要,开发一个项目选择什么样 ...
- MySQL to Redis
[TOC] 简介 使用mysql2redis可以非常便捷的将mysql中的数据导出到redis中去, 通常是需要一个select语句即可实现. 软件安装 // 安装apr + apr-util $ w ...