首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

纵谈迭代模式与IEnumerable

2012-11-23 
漫谈迭代模式与IEnumerable迭代模式与IEnumerable一个类型要实现foreach遍历就必须先实现IEnumerable接口

漫谈迭代模式与IEnumerable

迭代模式与IEnumerable

一个类型要实现foreach遍历就必须先实现IEnumerable接口和IEnumerator接口,IEnumerable接口和IEnumerator接口的工作原理也正是设计模式中迭代模式最好的例子。在理解IEnumerable接口和IEnumerator接口之前,先来理解迭代模式是如何实现的,对理解IEnumerable接口和IEnumerator接口的工作原理很有帮助。

Aggregate:聚合

Iterator:迭代器

Client:客户

纵谈迭代模式与IEnumerable

如图所示,聚合(Aggregate)与迭代器(Iterator)分别为抽象的接口,通过具体的实现,具体的聚合(ConcreteAggregate)与具体的迭代器(ConcreteIterator)分别建立了依赖关系和聚合关系,实现迭代器(Iterator)通过客户(Client)对聚合(Aggregate)的迭代操作。

OO版迭代模式

客户类(Client)

客户类(Client):是建立迭代模式的具体载体,最终是实现迭代器对聚合的客户类进行顺序迭代输出

public class Client    {        public string Name { get; set; }        public override string ToString()        {            return Name;        }    }

聚合(Aggregate):抽象聚合接口(Aggregate)创建一个用于查询自己的迭代器,它不关心自己存储的聚合元素,也不关心指定的迭代器是谁,因为那是具体的聚合类,而具体的聚合类(ConcreteAggregate)定义一个具体的客户类(Client)集合,同时实现了CreatedIterator()创建自己指定的迭代器(依赖关系0,便于检索也定义了索引器,Index属性,Count属性,Add方法用于添加集合元素操作。

聚合接口(Aggregate)

 public interface Aggregate    {        Iterator CreatedIterator();   }

具体的聚合类(ConcreteAggregate)实现聚合接口(Aggregate)

 public class ConcreteAggregate : Aggregate    {        //线性结构存储        protected List<Client> ClientList = new List<Client>();        //通过索引器以只读的方式将数据结构对外公开        public Client this[int index]        {            get            {                return ClientList[index];            }        }        public int Index { get; set; }        public int Count        {            get            {                return ClientList.Count;            }        }        public void Add(Client client)        {            ClientList.Add(client);        }        //指定所用的索引器,与索引器之间建立依赖关系        public Iterator CreatedIterator()        {            return new ConcreteIterator(this);        }    }

迭代器(Iterator)

迭代器的任务是查找出所要查找的集合元素,下一个元素Next(),当前元素Current(),重置元素Reset(),它也不关心将要查找哪个集合,具体实现的迭代器类(ConcreteIterator)则要负责实现Next(),Current(),Reset()成员,同时建立了与聚合类的关联关系,注意,在构造函数中对关联的集合类进行初始化操作,也正是这样聚合类才和迭代器形成依赖关系,注意依赖关系和关联关系是如何用代码的方式实现的

迭代器接口(Iterator)

public interface Iterator    {        bool Next();        Client Current();        void Reset();    }

具体的迭代器类(ConcreteIterator)实现迭代器接口(Iterator)

public class ConcreteIterator : Iterator    {        //与聚合类形成关联关系        ConcreteAggregate Agg = null;        public ConcreteIterator(ConcreteAggregate sch)        {             //指定所要查询的聚合类            Agg = sch;            Agg.Index = -1;        }        /// <summary>        /// Next()为指向下一个对象并        /// 判断是否到达集合的末尾        /// </summary>        public bool Next()        {          // 当聚合类的索引不等于集合长度时,继续向下查找,返回true并加一操作,否则返回false表示查询已结束            return (++Agg.Index != Agg.Count) ? true : false;        }        /// <summary>        /// Current()利用索引器取出当前集合元素        /// </summary>        public Client Current()        {            return Agg[Agg.Index];        }        /// <summary>        /// 重置下标        /// </summary>        public void Reset()        {            Agg.Index = -1;        }    }

主函数调用

 static void Main(string[] args)        {            //建立聚合类并添加聚合元素            ConcreteAggregate aggregate = new ConcreteAggregate();            aggregate.Add(new Client() { Name = "ABC" });            aggregate.Add(new Client() { Name = "CBA" });            aggregate.Add(new Client() { Name = "EEELab" });            //取出聚合类指定的迭代器,并对迭代器进行操作            Iterator iter = aggregate.CreatedIterator();            while (iter.Next())            {                Console.WriteLine(iter.Current());            }        }

IEnumerable接口和IEnumerator接口

在理解了前面的迭代模式后,在理解下面的IEnumerable接口和IEnumerator接口实现工作原理也就不成问题。你会发现这两个接口的实现正是一个典型的迭代模式。

客户类(Client)

 public class Client    {        public string Name { get; set; }        public override string ToString()        {            return Name;        }    }

聚合类(ConcreteAggregate)实现IEnumerable接口

public class ConcreteAggregate : System.Collections.IEnumerable    {        protected List<Client> ClientList = new List<Client>();        public int Index { get; set; }        public int Count        {            get            {                return ClientList.Count;            }        }        public Client  this[int index]        {            get            {                return ClientList[index];            }        }        public void Add(Client client)        {            ClientList.Add(client);        }        //对应于OO版本的CreatedIterator()方法        public System.Collections.IEnumerator GetEnumerator()        {            return new ConcreteIterator(this);        }    }

具体的迭代器类(ConcreteIterator)实现IEnumerator接口

public class ConcreteIterator : System.Collections.IEnumerator    {        ConcreteAggregate school = null;        public ConcreteIterator(ConcreteAggregate sch)        {            school = sch;            school.Index = -1;        }        //对应OO版本的Current()        object System.Collections.IEnumerator.Current        {            get { return school[school.Index]; }        }        //对应OO版本的Next()        public bool MoveNext()        {            school.Index++;            return (school.Index != school.Count) ? true : false;        }        //对应OO版本的Reset()        public void Reset()        {            school.Index = -1;        }    }

主函数调用

static void Main(string[] args)        {            //建立聚合类并添加聚合元素            ConcreteAggregate aggregate = new ConcreteAggregate();            aggregate.Add(new Client() { Name = "ABC" });            aggregate.Add(new Client() { Name = "CBA" });            aggregate.Add(new Client() { Name = "EEELab" });            //取出聚合类指定的迭代器,并对迭代器进行操作            IEnumerator Ienumerator = aggregate.GetEnumerator();            while (Ienumerator.MoveNext())            {                Console.WriteLine(Ienumerator.Current);            }        }

你会发现,IEnumerable接口和IEnumerator接口分别对应着聚合接口(Aggregate)和迭代器接口(Iterator),因此,实现IEnumerable接口和IEnumerator接口是实现迭代模式的典型例子,对理解如何让自己定义的类能够实现foreach遍历来说很有意义。

在主函数中用foreach调用聚合类(ConcreteAggregate)

static void Main(string[] args)        {            ConcreteAggregate aggregate = new ConcreteAggregate();            aggregate.Add(new Client() { Name = "ABC" });            aggregate.Add(new Client() { Name = "CBA" });            aggregate.Add(new Client() { Name = "EEELab" });            System.Collections.IEnumerator Ienumerator = aggregate.GetEnumerator();            while (Ienumerator.MoveNext())            {                Console.WriteLine(Ienumerator.Current);            }            foreach (Client item in aggregate)            {                Console.WriteLine(item.Name);            }        }

之所以foreach要用继承于IEnumerable接口的索引聚合类(ConcreteAggregate)是因为foreach直接调用索引集合的所继承IEnumerator接口的Current属性和MoveNext()成员方法。

下面是foreach的CIL代码,从代码可以看出foreach是在内部隐式的执行循环指令来实现我们在迭代模式中的循环操作,因此,从根本上说,执行foreach操作就是一个迭代模式的执行过程。

纵谈迭代模式与IEnumerable

foreach的CIL代码

.try

  {

    IL_0087:  br.s       IL_00a4  //跳转到执行MoveNext()的上一行

    IL_0089:  ldloc.s    CS$5$0001

    IL_008b:  callvirt   instance object [mscorlib]System.Collections.IEnumerator::get_Current()   //Current属性

    IL_0090:  castclass  IteratorNET.Client

    IL_0095:  stloc.2

    IL_0096:  nop

    IL_0097:  ldloc.2

    IL_0098:  callvirt   instance string IteratorNET.Client::get_Name()//Name属性

    IL_009d:  call       void [mscorlib]System.Console::WriteLine(string)

    IL_00a2:  nop

    IL_00a3:  nop

    IL_00a4:  ldloc.s    CS$5$0001

    IL_00a6:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()

    IL_00ab:  stloc.s    CS$4$0000

    IL_00ad:  ldloc.s    CS$4$0000

    IL_00af:  brtrue.s   IL_0089  //跳转回取Current属性的上一行

    IL_00b1:  leave.s    IL_00d0

  }  // end .try

  finally

  {

    IL_00b3:  ldloc.s    CS$5$0001

    IL_00b5:  isinst     [mscorlib]System.IDisposable

    IL_00ba:  stloc.s    CS$0$0002

    IL_00bc:  ldloc.s    CS$0$0002

    IL_00be:  ldnull

    IL_00bf:  ceq

    IL_00c1:  stloc.s    CS$4$0000

    IL_00c3:  ldloc.s    CS$4$0000

    IL_00c5:  brtrue.s   IL_00cf

    IL_00c7:  ldloc.s    CS$0$0002

    IL_00c9:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()

    IL_00ce:  nop

    IL_00cf:  endfinally

  }  // end handler

 

热点排行