[c#基础]集合foreach的必要条件和自定义集合
2014-02-14 20:14
495 查看
引言
最近翻看了之前的学习笔记,看到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 == 0 ? 0 : this.index > this.objArray.Length ? this.objArray.Length * 2 : this.objArray.Length; } } /// <summary> /// 集合实际元素个数 且只读 /// </summary> public int Count { get { return this.index; } } private int index; private object[] objArray; public MyArrayList() { index = 0; //初始化0长度的数组 this.objArray = new object[0]; } /// <summary> /// 添加元素 /// </summary> /// <param name="value">元素值</param> public void Add(object value) { if (index >= this.objArray.Length) { object[] newArray = index == 0 ? new object[this.objArray.Length + 4] : new object[this.objArray.Length * 2]; objArray.CopyTo(newArray, 0); objArray = newArray; objArray[index++] = value; } else { objArray[index++] = value; } } /// <summary> /// 添加数组 /// </summary> /// <param name="objs"></param> public void AddRange(object[] objs) { for (int i = 0; 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(1); list.Add(1); Console.WriteLine("count:" + list.Count); Console.WriteLine("Capacity:" + list.Capacity); list.Add(1); list.Add(1); list.Add(1); Console.WriteLine("count:" + list.Count); Console.WriteLine("Capacity:" + list.Capacity); list.Add(1); list.Add(1); list.Add(1); list.Add(1); list.Add(1); list.Add(1); Console.WriteLine("count:" + list.Count); Console.WriteLine("Capacity:" + list.Capacity); object[] arr = { 1, 2, 3, 4, 5, 6 }; 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 = -1; 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 = -1; } } }
测试,foreach语句,然后编译不再报错,说明已经成功了,结果如下:
这次后边不会多出逗号,原因实现了迭代器接口而迭代器继承自IDisposable接口,最后调用了Dispose()方法
代码下载,请戳这里:http://pan.baidu.com/s/1pJsGyHt
总结
foreach遍历in后面的对象需实现IEnumerable接口。迭代器概念可参考:http://msdn.microsoft.com/zh-cn/library/dscyy5s0(VS.80).aspx
东西比较基础,以上是个人理解,如理解有误,请指正,以免误人子弟。
相关文章推荐
- C# 通过IEnumberable接口和IEnumerator接口实现自定义集合类型foreach功能
- [c#基础]泛型集合的自定义类型排序
- C#使用yield关键字让自定义集合实现foreach遍历的方法
- c#之通过自定义集合彻底搞懂foreach这个语法糖
- C#控制台基础 int类型list集合forEach方法实例
- C#使用yield关键字让自定义集合实现foreach遍历的方法
- More Effective C# 第21条、第22条 实例代码解析(可比较 可排序 自定义对象集合完整演示) IEquatable, IComparable,IEnumerable
- c# Array或List有个很实用的ForEach方法,可以直接传入一个方法对集合中元素操作
- C#基础精华03(常用类库StringBuilder,List<T>泛型集合,Dictionary<K , V> 键值对集合,装箱拆箱)
- 黑马程序员_WPF(WPF认识,Sender,C#基础加强类继承,集合,Xaml,控件通用属性)
- 黄聪:C#使用能够foreach对hashtable、List遍历时“集合已修改;可能无法执行枚举操作。”错误
- C#基础-058 List集合、HashSet集合、HashTable集合、StringBuilder与String运行效率比较
- c#基础语言编程-集合
- 遇到的问题-----c#操作mongodb用foreach遍历集合报错curcor not found
- C#基础精华03(常用类库StringBuilder,List<T>泛型集合,Dictionary<K , V> 键值对集合,装箱拆箱)
- Java基础知识强化之集合框架笔记40:Set集合之HashSet存储自定义对象并遍历
- C# List集合基础操作
- c#基础加强--集合
- C#中出现“集合已修改;可能无法执行枚举操作”错误 foreach list.Remove()
- [C#基础知识]专题十三:全面解析对象集合初始化器、匿名类型和隐式类型