C#中foreach语句的迭代器实现机制
C#中的foreach语句可用于循环遍历某个集合中的元素,而所有的只要支持了IEnumerable或IEnumerable<T>泛型接口的类型都是可以
用foreach遍历的。其具体的遍历实现过程就是利用C#中的迭代器中的方法来按照特定顺序遍历的。在.NET中IEnumerator和IEnumerator<T>
就是对迭代器的抽象,如果要自定义的类型也支持foreach循环则首先须要声明该类支持IEnumerable或IEnumerable<T>接口,然后再去实现自己
的支持了IEnumerator<T>的迭代器类型;唉,先看代码吧!
---------YYC
For Example:
// 实现了IEnumerable<T>泛型接口的类
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Pra6
{
public enum PhoneType
{
家庭电话,办公电话,手机,小灵通,传真
} class Phones : IEnumerable<string>
{
private string[] phones;
private int count = 0;
public int Count {
get { return count; }
}
public string this[PhoneType type]
{
get {
return phones[(int)type];
}
set {
int index = (int)type;
if (phones[index] == null && value != null)
{
count++;
}
else
if (phones[index] != null && value == null)
{
count--;
}
phones[index] = value;
}
} public Phones()
{
phones = new string[5];
}
public void CopyTo( Array array,int index)
{
foreach(string s in phones )
{
if (s != null)
array.SetValue(s,index++);
}
}
public IEnumerator<string > GetEnumerator()//返回迭代器
{
return new MyEnumerator<string>(phones);
}
IEnumerator IEnumerable.GetEnumerator()//返回迭代器,由于IEnumerable<T>接口也继承了IEnumerable接口所以出于兼容性考虑,最后也要实现该方法,但内容可//以和上面的代码一样
{
return this.GetEnumerator();
} }
}
// 实现了IEnumerator<T>的迭代器类型
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace Pra6
{
class MyEnumerator<T>:IEnumerator<T>
{
private int current;
internal T[] array;
public T Current {//返回当前数据
get { return array[current]; }
}
public MyEnumerator(T[] array)
{
this.array = array;
this.current = -1;
}
public bool MoveNext()//使迭代器移向下一项
{
if (++current == array.Length)
return false ;
return true;
}
object IEnumerator.Current//返回当前的数据,同样也是出于兼容性的考虑
{
get { return array [current];}
}
public void Reset()//重设迭代器,以便重新开始遍历
{
current = -1;
}
void IDisposable.Dispose()
{ } }
}
//调用过程
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms; namespace Pra6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
LinkedList<string> aa = new LinkedList<string>();
string a1 = "aa";
string a2 = "bb";
string a3 = "cc";
string a4 = "dd";
LinkedListNode<string> b1 = aa.AddFirst(a1);
b1 = aa.AddAfter(b1,a2);
b1 = aa.AddAfter(b1, a3);
aa.AddLast(a4);
textBox1.Text = null ;
foreach (string a in aa )
{
textBox1.Text += " " + a;
}
b1 = b1.Next;
b1 = b1.Next; textBox1.Text += b1.Value; } private void textBox1_TextChanged(object sender, EventArgs e)
{ } private void button2_Click(object sender, EventArgs e)
{
Phones ph = new Phones();
ph[PhoneType.办公电话] = "111";
ph[PhoneType.传真] = "222";
ph[PhoneType.家庭电话] = "333";
ph[PhoneType.手机] = "444";
ph[PhoneType.小灵通] = "555";
textBox1.Text = null;
//方法一:调用foreach实现
foreach(string s in ph)
{
textBox1.Text += s+" ";
} //调用迭代器实现遍历。
IEnumerator<string> iter = ph.GetEnumerator();
while(iter.MoveNext())
{
textBox1.Text += iter.Current + " ";
}
}
}
}
其实,在.NET的中间语言是并不支持foreach语句的,而是C#的编译器可以将程序中的foreach语句转换成
对迭代器操作的while或for语句的循环遍历,例如:上面的:
foreach(string s in ph)
{
textBox1.Text += s+" ";
}
其真实的执行代码就是
IEnumerator<string> iter = ph.GetEnumerator();
while(iter.MoveNext())
{
textBox1.Text += iter.Current + " ";
}
所以当我们懂了这个实现原理后我们也是可以去定义我们自己的可以支持foreach的类型了,
但是需要值得一提的是并非我们每次都需要去显示的自己定义我们的迭代器类型,C#语言本身
一大特色就是快速开发吗,这是因为C#中为迭代器模式提供了一种简化实现方式,即使用yield returne语句。
例如:将上面的Phones类中的GetEnumerator()直接改为下面的方式,不用再去定义迭代器类型,就能直接
使用foreach语句:
public IEnumerator<string> GetEnumerator()
{
for (int i = 0; i < 5;i++ )
{
if (phones[i]!=null)
yield return phones[i];
}
}
C#中foreach语句的迭代器实现机制的更多相关文章
- C#基础知识---迭代器与Foreach语句
一.Foreach语句简介 在C# 1.0中我们经常使用foreach来遍历一个集合中的元素,然而如果一个集合要支持使用foreach语句来进行遍历,这个集合一般需要IEnumerable或IEnum ...
- Java中的可变参数以及foreach语句
Java中的可变参数的定义格式如下: 返回值类型 方法名称(类型 ... 参数名称){} foreach语句的格式如下: for ( 数据类型 变量名称 :数据名称){ ... } public ...
- C#中的foreach语句与枚举器接口(IEnumerator)及其泛型 相关问题
这个问题从<C#高级编程>数组一节中的foreach语句(6.7.2)发现的. 因为示例代码与之前的章节连贯,所以我修改了一下,把自定义类型改为了int int[] bs = { 2, 3 ...
- 【Java学习笔记之十】Java中循环语句foreach使用总结及foreach写法失效的问题
foreach语句使用总结 增强for(part1:part2){part3}; part2中是一个数组对象,或者是带有泛性的集合. part1定义了一个局部变量,这个局部变量的类型与part2中的对 ...
- PHP:第二章——PHP中的foreach语句
foreach语句提供了遍历数组的 <?php header("Content-Type:text/html;charset=utf-8"); $arr=array(&quo ...
- 浅析foreach语句
本篇是我对于foreach语句(增强for)的总结: 我的总结流程如下: 1.先整体说明增强for遍历集合与数组之间的区别. 2.通过一维数组来说明(给出反编译的源码,形成对照). 3.通过二维数组来 ...
- foreach语句的用法
foreach语句: foreach语句是for语句的特殊简化版本,不能完全取代for语句,但任何foreach语句都可以改写为for语句版本.foreach并不是一个关键字,习惯上将这种特殊的for ...
- 编写高质量代码改善C#程序的157个建议——建议30:使用LINQ取代集合中的比较器和迭代器
建议30:使用LINQ取代集合中的比较器和迭代器 LINQ提供了类似于SQL的语法来实现遍历.筛选与投影集合的功能. static void Main(string[] args) { List< ...
- 6.2 C# 2:利用 yield 语句简化迭代器
class Program { static void Main(string[] args) { object[] values = new object[] { "a", &q ...
随机推荐
- linux 使用者管理
1.用户标识符 UID 用户ID GID 用户组ID 2./etc/passwd 文件结构 id范围:0系统管理员|1~499 (系统账号)|500~65535 可登录账号
- mobile web 手机开发
1. -webkit-tap-highlight-color -webkit-tap-highlight-color:rgba(255,255,255,0); 用来把android上点击网页时出现 ...
- oracle db_unnqiue_name db_name sid_name instance_name service_name
- 在基类中的析构函数声明为virtual
#include <iostream> using namespace std; class Father { public: ~Father() { cout << &quo ...
- hdu 2203亲和串 (kmp)
#include<cstdio>#include<iostream>#include<cstring>#include<string>using nam ...
- wpf 如何设置滚动条在超出范围的时候才显示?(转)
VerticalScrollBarVisibility="Auto" 垂直自动显示 HorizontalScrollBarVisibility="Auto" ...
- slots
class Student(object): pass s = Student() s.name = 'Michael' print(s.name) def set_age(self, age): s ...
- 系统变量写在.bash_profile和.bashrc的区别
今天配置一个代理,正儿八经的把我搞蒙了,不就是export http_porxy=xxx.xxx.xxx.xxx:xxxx 然后重启服务service network restart ,依然连接不了外 ...
- C# 课堂总结3-语句
一.顺序语句 二.条件,分支语句 1.if语句 关键是能够熟练运用 if的嵌套.要考虑好所有的情况. 如果说 条件是两种+情况相互对应的,那么就可以只用 if 与else .但必须要想好 每个else ...
- error C2018: unknown character '0xa1'
调试程序时出现 error C2018: unknown character '0xa1',代码行中加入的有编译器不能识别的字符,才发现由空格引起的,删除掉就ok了.