浅析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 ...
随机推荐
- altium designer 里如何设置PCB默认字符默认大小(PCB丝印)
注意:此操作只对新导入的元件生效.
- SQL Server Profiler参数说明
上图依次说明为: TextDate 依赖于跟踪中捕获的事件类的文本值: ApplicationName 创建 SQL Server 连接的客户端应用程序的名称.此列由该应用程序传递的值填充,而不是由所 ...
- iOS 应用数据存储的常用方式
iOS 开发中,经常会有将数据存储到本地的需求.比如一些数据的缓存,或者记录下用户的账号密码,记录下下次是否自动登录等,这些都需要将数据记录到本地.iOS中,数据存储到本地的常见方式有三种: 一: 使 ...
- Struts2中的session、request、respsonse获取方法
个人对于struts有一种复杂的心情,平心而论,struts2是个人最早接触到的的框架,在学校的时候就已经开始学习了,大四毕业设计,无疑用的还是struct,那时候SSH还是很流行的,后来出来实习,直 ...
- git拉取远程分支并创建本地分支和Git中从远程的分支获取最新的版本到本地
git拉取远程分支并创建本地分支 一.查看远程分支 使用如下Git命令查看所有远程分支: git branch -r 二.拉取远程分支并创建本地分支 方法一 使用如下命令: git checkout ...
- linux和windows文件名称长度限制
Linux文件名称的长度限制是255个字符 windows下全然限定文件名称必须少于260个字符,文件夹名必须小于248个字符. linux下文件数.文件夹数.文件名称长度的各种限制 下面測试都是在没 ...
- MVC4网站发布到windows server 2003服务器
在windows server 2003上部署MVC4的网站,需要进行以下工作 用VS2013新建项目 在创建项目的时候选择的矿建为.NET Framework4,然后选择[ASP.NET MVC4 ...
- mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication的解决方法
直接命令行操作没有问题,但是PHP连接就会报上面的错误. SET old_passwords =0; USE mysql; UPDATE user SET password =PASSWORD('yo ...
- Java开发手冊 Java学习手冊教程(MtJava开发手冊)
本文档的版权归MtJava文档小组全部,本文档及其描写叙述的内容受有关法律的版权保护,对本文档内容的不论什么形式的非法复制.泄露或散布.将导致对应的法律责任. MtJava仅仅是一个学习Java的简化 ...
- Config the Android 5.0 Build Environment
In this document Choosing a Branch Setting up a Linux build environment Installing the JDK ...