引言

最近翻看了之前的学习笔记,看到foreach,记得当时老师讲的时候,有点犯浑,不是很明白,这好比,上小学时,你不会乘法口诀,但是随着时间的增长,你不自觉的都会了,也悟出个小道理,有些东西,你当时不太懂,但随着你的阅历和经验的增长,有那么一天你会恍然大悟,哦,原来是这样。

自定义集合类

提到foreach就不得不说集合,那么就先从自定义的集合开始吧。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Wolfy.自定义集合
{
/// <summary>
/// 自定义集合类
/// </summary>
public class MyArrayList
{
/// <summary>
/// 集合的容量属性 成倍数增加0,4,8,且只读
/// </summary>
public int Capacity
{
get
{
return this.objArray.Length == ? : this.index > this.objArray.Length ? this.objArray.Length * : this.objArray.Length;
}
}
/// <summary>
/// 集合实际元素个数 且只读
/// </summary>
public int Count
{
get
{
return this.index;
}
}
private int index;
private object[] objArray;
public MyArrayList()
{
index = ;
//初始化0长度的数组
this.objArray = new object[];
}
/// <summary>
/// 添加元素
/// </summary>
/// <param name="value">元素值</param>
public void Add(object value)
{
if (index >= this.objArray.Length)
{
object[] newArray = index == ? new object[this.objArray.Length + ] : new object[this.objArray.Length * ];
objArray.CopyTo(newArray, );
objArray = newArray;
objArray[index++] = value;
}
else
{
objArray[index++] = value;
}
}
/// <summary>
/// 添加数组
/// </summary>
/// <param name="objs"></param>
public void AddRange(object[] objs)
{
for (int i = ; i < objs.Length; i++)
{
this.Add(objs[i]);
}
}
}
}

不知道自定义的集合和ArrayList是否一样,可以简单的测试一下。

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Wolfy.自定义集合
{
class Program
{
static void Main(string[] args)
{
ArrayList list = new ArrayList();
//MyArrayList list = new MyArrayList();
Console.WriteLine("count:" + list.Count);
Console.WriteLine("Capacity:" + list.Capacity);
list.Add();
list.Add();
Console.WriteLine("count:" + list.Count);
Console.WriteLine("Capacity:" + list.Capacity);
list.Add();
list.Add();
list.Add();
Console.WriteLine("count:" + list.Count);
Console.WriteLine("Capacity:" + list.Capacity);
list.Add();
list.Add();
list.Add();
list.Add();
list.Add();
list.Add();
Console.WriteLine("count:" + list.Count);
Console.WriteLine("Capacity:" + list.Capacity);
object[] arr = { , , , , , };
list.AddRange(arr);
Console.WriteLine("count:" + list.Count);
Console.WriteLine("Capacity:" + list.Capacity);
Console.Read();
}
}
}

此时是.Net中的ArrayList,结果:

自定义的集合,结果:

输出结果一样,那么现在用foreach遍历,自定义集合中的元素。F6编译,会提示错误。

foreach语句

其实foreach是怎样工作的呢?

众所周知foreach中in后面的对象应该是实现IEnumerable接口的,程序运行时本质是在调用IEnumerable的GetEnumerator函数来返回一个IEnumerator对象,foreach就是利用IEnumerator对象的Current,MoveNext和Reset成员来进行一段数据的枚举。简单的代码实现如下:

             //System.Collections下的IEnumerator
IEnumerator enumerator = this.objArray.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}

将这个代码放在自定义集合中,定义一个方法GetArray(),然后测试一下

         /// <summary>
/// 得到所有的元素
/// </summary>
public void GetArray()
{
//System.Collections下的IEnumerator
IEnumerator enumerator = this.objArray.GetEnumerator();
while (enumerator.MoveNext())
{
Console.Write(enumerator.Current+“,”);
}
}

测试结果:

你运行会发现多出很多逗号,原因是执行后,enumerator没有被Dispose掉,而继承IDisposable的迭代器(IEnumerator)在foreach结束后会被正确处理掉(调用Dispose方法)。

自定义集合实现IEnumerable接口

实现IEnumerable接口必须实现它里面的成员GetEnumerator()方法:

         public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}

该方法的返回值为实现了IEnumerator接口的类的对象。那么现在需要定义一个实现了该接口的类。

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Wolfy.自定义集合
{
public class MyEnumerator : IEnumerator
{
/// <summary>
/// 返回当前指针指向的元素的值
/// </summary>
public object Current
{
get { throw new NotImplementedException(); }
}
/// <summary>
/// 将指针向前移动1位,并判断当前位有没有元素.指针默认在-1位置
/// </summary>
/// <returns></returns>
public bool MoveNext()
{
throw new NotImplementedException();
}
/// <summary>
/// 重置
/// </summary>
public void Reset()
{
throw new NotImplementedException();
}
}
}

迭代需要数组参数,在构造函数中将自定义集合中的数组传进来,并且在MoveNext中需要判断指针是否移动到数组的末尾,那么需要数组的长度。
MyArrayList中GetEnumerator()方法实现

         public IEnumerator GetEnumerator()
{
return new MyEnumerator(this.objArray, this.Count);
}

MyEnumerator类

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Wolfy.自定义集合
{
public class MyEnumerator : IEnumerator
{
/// <summary>
/// 指针的默认位置
/// </summary>
private int index = -;
private object[] objArray;
/// <summary>
/// 数组长度
/// </summary>
private int count;
public MyEnumerator(object[] objArray, int count)
{ this.objArray = objArray;
this.count = count;
}
/// <summary>
/// 返回当前指针指向的元素的值
/// </summary>
public object Current
{
get { return this.objArray[index]; }
}
/// <summary>
/// 将指针向前移动1位,并判断当前位有没有元素.指针默认在-1位置
/// </summary>
/// <returns></returns>
public bool MoveNext()
{
index++;//指针首先向前移动一位
if (index < this.count)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// 重置
/// </summary>
public void Reset()
{
index = -;
}
}
}

测试,foreach语句,然后编译不再报错,说明已经成功了,结果如下:

这次后边不会多出逗号,原因实现了迭代器接口而迭代器继承自IDisposable接口,最后调用了Dispose()方法

代码下载,请戳这里:http://pan.baidu.com/s/1pJsGyHt

总结

foreach遍历in后面的对象需实现IEnumerable接口。

迭代器概念可参考:http://msdn.microsoft.com/zh-cn/library/dscyy5s0(VS.80).aspx

东西比较基础,以上是个人理解,如理解有误,请指正,以免误人子弟。

最新文章

  1. linux下安装及配置和启动memcached
  2. 读《程序员的SQL金典》[2]--函数
  3. [自制简单操作系统] 7、多任务(二)——任务管理自动化&amp;任务休眠
  4. spm完成dmp在windows系统上导入详细过程
  5. POJ 3468 (线段树 区间增减) A Simple Problem with Integers
  6. python练习程序(c100经典例2)
  7. 用shell查找某个目录下最大文件
  8. 在linux下的apache配置https协议,开启ssl连接
  9. Best jQuery Plugins of the Month – May 2014
  10. 图的连通性:有向图强连通分量-Tarjan算法
  11. [转] 传说中的WCF(2):服务协定的那些事儿
  12. mysql在cmd命令下执行数据库操作
  13. 安装Linux虚拟系统
  14. Docker proxy
  15. linux仅修改文件夹权限 分别批量修改文件和文件夹权限
  16. Django REST framework 简介
  17. Django 日志
  18. 对象 Object
  19. 20145232 韩文浩 《Java程序设计》第2周学习总结
  20. Python做int()强制类型转换的时候,小数是如何取舍的?

热门文章

  1. asp.net连接SQL SERVER 2012的方法
  2. windows 进程管理器中的内存是什么意思?
  3. docker常用术语命令
  4. Storm calculate pv
  5. java读取word内容
  6. codeforces 719E E. Sasha and Array(线段树)
  7. NYOJ-301递推求值
  8. Java虚拟机详解04----GC算法和种类【重要】
  9. VC2010中去掉红绝下划线
  10. python 维吉尼亚