在日常开发工作中,我们发现很多对象都能通过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原理的更多相关文章

  1. Foreach原理

    本质:实现了一个IEnumerable接口, 01.为什么数组和集合可以使用foreach遍历? 解析:因为数组和集合都实现了IEnumerable接口,该接口中只有一个方法,GetEnumerato ...

  2. .net学习之集合、foreach原理、Hashtable、Path类、File类、Directory类、文件流FileStream类、压缩流GZipStream、拷贝大文件、序列化和反序列化

    1.集合(1)ArrayList内部存储数据的是一个object数组,创建这个类的对象的时候,这个对象里的数组的长度为0(2)调用Add方法加元素的时候,如果第一次增加元神,就会将数组的长度变为4往里 ...

  3. 浅析bootstrap原理及优缺点

    网格系统的实现原理,是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统   网格系统的实现原理,是通过定义 ...

  4. Array.forEach原理,仿造一个类似功能

    Array.forEach原理,仿造一个类似功能 array.forEach // 设一个arr数组 let arr = [12,45,78,165,68,124]; let sum = 0; // ...

  5. 浅析WebSocket 原理

    浅析WebSocket 原理 长恨此身非我有,何时忘却营营. 简介:先简单了解下WebSocket 原理,日后的使用中再进一步深入研究~ 一.什么是WebSocket WebSocket 是HTML5 ...

  6. 浅析Kerberos原理,及其应用和管理

    文章作者:luxianghao 文章来源:http://www.cnblogs.com/luxianghao/p/5269739.html  转载请注明,谢谢合作. 免责声明:文章内容仅代表个人观点, ...

  7. C#学习笔记:foreach原理

    这篇随笔是对上一篇随笔C#关键字:yield的扩展. 关于foreach 首先,对于 foreach ,大家应该都非常熟悉,这里就简单的描述下. foreach 语句用于对实现  System.Col ...

  8. C#foreach原理

    本文主要记录我在学习C#中foreach遍历原理的心得体会. 对集合中的要素进行遍历是所有编码中经常涉及到的操作,因此大部分编程语言都把此过程写进了语法中,比如C#中的foreach.经常会看到下面的 ...

  9. Foreach 原理

    public class Person { private string[] friends = { "asf", "ewrqwe", "ddd&qu ...

随机推荐

  1. Oracle-数据实现竖排打印

    --存放重证评分的数据表create table ZZPFapache2(  ZZ_datetime DATE,   --时间  ZZ_zongfen INTEGER, --总分  ZZ_shiwan ...

  2. SignalTap II逻辑分析仪的使用

    一.例子 我们使用如图1所示的verilog代码所实现的开关电路作为例子.这个电路把DE系列开发板上的前8个开关简单的和对应的8个红色LED相连接.它是这样工作的:在时钟(CLOCK_50)的上升沿读 ...

  3. 总结一下ERP .NET程序员必须掌握的.NET技术

    总结一下ERP .NET程序员必须掌握的.NET技术,掌握了这些技术工作起来才得心应手   从毕业做.NET到现在,有好几年了,自认为只能是达到熟练的水平,谈不上精通.所以,总结一下,自己到底熟练掌握 ...

  4. MySQL 子查询 EXISTS 和 NOT EXISTS

    MySQL EXISTS 和 NOT EXISTS 子查询 MySQL EXISTS 和 NOT EXISTS 子查询语法如下: SELECT ... FROM table WHERE EXISTS ...

  5. Innodb 锁 (简单笔记)

    看过很多innodb锁的文章,已经明白的就不写了,简单做个笔记   Innodb 锁的兼容性: 1.意向锁和意向锁之间都是兼容的 2.X(排他锁)与任何锁都是不兼容的 3.排他意向锁 IX 于S锁是不 ...

  6. 本地或者是koala软件编译less文件为css

    背景: 事情的起因是这般的,平时工作是在线上办公,样式是使用less来写,于是乎,这样我从线上download下来的less文件无法直接在自己的本地环境运行.有一个问题就是我要把less文件先编译成c ...

  7. UIView的Touch事件UIControlEvents详解

    首先,UIControlEvents有这个几种: UIControlEventTouchDown = << , // on all touch downs UIControlEventTo ...

  8. 关于expanded一级二级菜单数据的分组排序

    最新再弄关于expandedlistview相关的东西,所以需求是需要对一级菜单根据时间排序,同时二级菜单也需要根据时间排序,距离现在最近的时间显示在最前面. 效果就是如下: --group2  -- ...

  9. java推断字符串是否为乱码

    项目中有一个功能 在IE中GET方式提交会产生乱码 但有两个入口都会走这同一段代码 固不能直接转码,所以要进行推断传过来的该值是不是乱码 可用下面方式验证: java.nio.charset.Char ...

  10. 实例源码--ZXing识别条形码和二维码识别源码

      下载源码 技术要点: 1.ZXing库的 使用 2.识别条形码和二 维码 3.自定义视图 4.源码带有非常详 细的中文注释 ...... 详细介绍: 1.ZXing库 ZXing是个很经典的条码/ ...