c#之通过自定义集合彻底搞懂foreach这个语法糖
来源:互联网 发布:一元抽奖的软件是什么 编辑:程序博客网 时间:2024/06/08 16:48
**我直接贴出代码,每个代码的作用我已经注释上,后面在单独分析下语法糖,一定要上机测试。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;using System.Text;using System.Threading.Tasks;namespace 基本功修炼{ class MyEnnumberator : IEnumerator //自定义迭代接口 继承于IEnumerator 成为子类 { private int i = 0; //索引下标,用于遍历集合中的元素 private ArrayList _al; //保存ArrayList集合的变量 /// <summary> /// 构造函数 /// </summary> /// <param name="al"></param> public MyEnnumberator(ArrayList al) //自定迭代器的构造函数,并且接受外部传来的一个集合,保存在当前字段里 { _al = al; } // // 摘要: // 获取集合中的当前元素。 // // 返回结果: // 集合中的当前元素。 public object Current { get { return _al[i++]; //返回当前索引对象的person元素,并且索引+1,这样下次返回就下个元素 } } // // 摘要: // 将枚举数推进到集合的下一个元素。 // // 返回结果: // 如果枚举数已成功地推进到下一个元素,则为 true;如果枚举数传递到集合的末尾,则为 false。 // // 异常: // T:System.InvalidOperationException: // 创建枚举器后,已修改该集合。 public bool MoveNext() //用来判断当前集合中还有没有可遍历输出的元素不 { if(i > _al.Count - 1) { return false; }else { return true; } } // // 摘要: // 将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。 // // 异常: // T:System.InvalidOperationException: // 创建枚举器后,已修改该集合。 public void Reset() { i = 0; //索引归为0 下次访问的时候就是从第一个元素开始 } } class Person //数据类型,作为存入集合中的测试数据元素 { public string name; //字段 用于输出测试用 public Person(string name) //构造函数 { this.name = name; } public override string ToString() //重写ToString为了输出这个类的字段名称而不是自带的输出类名和名称空间 { return name; } } class PersonCollection : IEnumerable //表示可遍历可枚举 { private ArrayList _al = new ArrayList(); /// <summary> /// 实现枚举遍历接口 /// </summary> /// <returns></returns> public IEnumerator GetEnumerator() //实现的一个接口,通过这个方法即可让当前集合使用foreach这个语法糖,注释掉这个方法不能用foreach { return new MyEnnumberator(_al); //这个是使用了里氏替换原则,子类可以当父类使用 } //索引器 public Person this[int index] { get { return _al[index] as Person; } } public void Add(Person p) //往当前集合添加一个人的元素 { _al.Add(p); //内部用的是ArrayList的添加方法 } public void Clear() { _al.Clear(); } /// <summary> /// 插入 /// </summary> /// <param name="index"></param> /// <param name="value"></param> public void Insert(int index, Person value) { _al.Insert(index, value); } /// <summary> /// 查询特定对象在集合中的位置 /// </summary> /// <param name="p"></param> /// <returns></returns> public int IndexOf(Person p) { return _al.IndexOf(p); } /// <summary> /// 按照索引下标删除制定对象 /// </summary> /// <param name="removeIndex"></param> public void RemoveAt(int removeIndex) { _al.RemoveAt(removeIndex); } /// <summary> /// 删除指定对象 /// </summary> /// <param name="p"></param> public void Remove(Person p) { if(_al.Contains(p)) { int intPostion = IndexOf(p); RemoveAt(intPostion); } } } class Program { static void Main(string[] args) { PersonCollection collection = new PersonCollection(); //测试add方法 collection.Add(new Person("马天宇")); collection.Add(new Person("马天")); collection.Add(new Person("雄霸")); Console.WriteLine(collection[0]); collection.Insert(0, new Person("插队的大佬"));//测试插入功能 Console.WriteLine(collection[0]); Console.WriteLine("\n开始遍历输出集合当中的元素:"); foreach (var item in collection) //测试foreach功能 { Console.WriteLine(item); } } }}
当你们看到这来的时候我希望你们已经运行代码完毕,如果没有上代码到VS没多少效果
那么现在我想你们最疑惑的是foreach到达是怎么迭代的。我想最简单的办法就是下断点调试
下面我在182行处断点
看截图
现在我单步调试已经要执行183行,那么第一步是做什么,肯定是要 得到collection,然后会从collection中寻找这个方法 public IEnumerator GetEnumerator() 没有找到就会报错找到后就执行
大家仔细看流程已经跑到这里,现在马上要跑 MyEnnumberator(_al)构造函数,并且要得到外部送进来的ArrayList集合,
大家好好看,通过构造函数的命令,操作系统就会分配好内存,然后马上会执行构造函数里面的代码给我们的自定义集合类指定ArrayList集合用于存储人这个数据,
现在在执行代码 看看往哪里跑;
看的出来执行完自定义迭代器构造函数之后会马上回调PersonCollection这里,开始接受也是得到迭代器对象,这样forech那边就拿到了迭代器。完成准备工作。
继续执行会跑到这个代码中判断集合还有没有元素
如果有的话,就会执行
内部代码就会自动给你选择一个元素塞在这个item变量当中,然后执行输出
还是被屏蔽了得到元素的细节,其实吧我们对这个得到元素的细节就不要深究了。我们知道必须得到一个迭代器的准备工作才可以开始,那么我们就必须先自定义一个迭代器 和实现一个必须实现的接口就可以。
IEnumerator IEnumerable 实现他们当中的全部接口 并且注意是返回
public IEnumerator GetEnumerator() //实现的一个接口,通过这个方法即可让当前集合使用foreach这个语法糖,注释掉这个方法不能用foreach
{
return new MyEnnumberator(_al); //这个是使用了里氏替换原则,子类可以当父类使用
}
注意最内部的集合是ArrayList,并且这个集合是自定义迭代器类里面new出来的,然后传给定义集合对象当中。**
好像还不能看清forea到达做了什么,那么我们不用for和forech该怎么输出集合对象保存的元素呢。
下面我针对HashTable做个试验
大家好好对比下,上机测试啊。forech就是 微软为了方便我们用的语法糖,如果我们用下面的代码去遍历迭代是不是没有forech清晰啊。所以我们就要求我们需要迭代的集合必须继承具体接口,就是因为用到的代码是确定的。
是不是还没搞清为什么我们在进行foreach的时候,我们不能对集合元素进行删除或者增加的,
首先我们要先学会用其他的代码来代替foreach这个语法糖, 比如我们用图的下面代码,如果我们在加上在循环里检测集合元素是不是变了,如果变了就抛一个InvaidOperationException 表示我们的操作是无效的,这样就解决了我们的疑问吗,还有一点就是编译器在编译代码之后,你觉得还是foreach吗,肯定不是,这个是面向程序员的,方便,但是真正面向计算机就是复杂的等同功能的代码。 所以啊微软给我们方便的同时也给了我们很多疑惑啊。
- c#之通过自定义集合彻底搞懂foreach这个语法糖
- 彻底搞懂C#之Yield Return语法的作用和好处
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
- c#创建自定义集合类并使之支持使用foreach迭代
- Java语法糖之foreach
- Java语法糖之foreach
- C#学习之自定义类实现foreach
- C#学习之自定义类实现foreach
- [Java集合] 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联(各大公司面试经常遇到)
- 彻底搞懂 RxJava
- 彻底搞懂CoordinatorLayout
- 彻底搞懂CNN
- 彻底搞懂CNN
- 彻底搞懂CNN
- 几分钟让你彻底搞懂 c#之using和try-catch-finaly的区别和联系
- 看完这个帖子让你彻底搞懂Websocket原理(转载)
- 彻底搞懂HashMap,HashTable,ConcurrentHashMap之关联.
- 看书 ecma-262
- 关于button自动提交表单事件
- 将设计稿图标制作成iconfont(ps cs6 + ai cs6)
- Dubbo/Dubbox的服务暴露(一)
- 结构体
- c#之通过自定义集合彻底搞懂foreach这个语法糖
- 绑定service报错: java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.lubo.fmdigit
- 【bzoj3011】[Usaco2012 Dec]Running Away From the Barn
- 解决夜神连接不上
- 图像存储格式
- android事件总线EventBus3.0简单使用
- 用Excel表格拆分一行里的内容
- EF从数据库更新Module
- 源码浅析 ArrayList、Vector、LinkedList 的区别