不能不说的C#特性-迭代器(上)及一些研究过程中的副产品

系列文章导航:

走进Linq--Linq横空出世篇

走进Linq-辉煌的背后

走进Linq-Linq大观园

不能不说的C#特性-对象集合初始化器

不能不说的C#特性-匿名类型与隐式类型局部变量

不能不说的C#特性-扩展方法

不能不说的C#特性-匿名方法和Lambda表达式

不能不说的C#特性-迭代器(上)及一些研究过程中的副产品

不能不说的C#特性-迭代器(下),yield以及流的延迟计算

走进Linq-Linq to Objects(上)基础篇

走进Linq-Linq to Objects(下)实例篇

走进Linq-Linq to SQL感性认识篇

走进Linq-Linq to SQL How do I(1)

走进Linq-Linq to SQL How do I(2)

走进Linq-Linq to SQL How do I(3)

走进Linq-How do I(4)拾遗补零篇第一节

走进Linq-Linq to SQL源代码赏析 Table的获取过程

走进Linq-Linq to SQL源代码赏析之Provider的初始化

走进Linq-Linq to SQL源代码赏析,通过Linq to SQL看Linq


提到迭代器我们不能不想到迭代器模式,那我就以迭代器模式作为开场白。

在我们的应用程序中常常有这样一些数据结构:

它们是一个数据的集合,如果你知道它们内部的实现结构就可以去访问它们,它们各自的内部存储结构互不相同,各种集合有各自的应用场合.说到这里大家可能想出一大堆这样的集合了:List,Hashtable,ArrayList等等。这些集合各自都有各自的个性,这就是它们存在的理由。但如果你想遍历它你必须知道它内部的存储细节,作为一个集合元素,把内部细节暴露出来肯定就不好了,这样客户程序就不够稳定了,在你更换集合对象的时候,比如List不能满足需求的时候,你换成Hashtable,因为以前的客户程序过多的关注了List内部实现的细节,所以不能很好的移植。而迭代器模式就是为解决这个问题而生的:

提供一种一致的方式访问集合对象中的元素,而无需暴露集合对象的内部表示。

比如现在有这样一个需求,遍历集合内的元素,然后输出,但是并不限定集合是什么类型的集合,也就是未来集合可能发生改变。

思考:

集合会发生改变,这是变化点,集合改变了,遍历方法也改变,我们要保证遍历的方法稳定,那么就要屏蔽掉细节。找到了变化点那我们就将其隔离起来(一般使用interface作为隔离手段):假设所有的集合都继承自ICollection接口,这个接口用来隔离具体集合的,将集合屏蔽在接口后面,作为遍历我们肯定需要这样一些方法:MoveNext,Current,既然ICollection负责数据存储,职责又要单一,那么就新建立一个接口叫做Iterator吧,每种具体的集合都有自己相对应的Iterator实现:

下面是一个简易的实现代码:

/// 
/// 集合的接口
/// 
    public interface ICollection
    {
        
int Count { get; }
        
/// 
        
/// 获取迭代器
        
/// 
        
/// 迭代器
        Iterator GetIterator();
    }
    
/// 
    
/// 迭代器接口
    
/// 
    public interface Iterator
    {
        
bool MoveNext();

        
object Current { get; }
    }

    
public class List : ICollection
    {
        
private const int MAX = 10;
        
private object[] items;
        
public List()
        { 
            items 
= new object[MAX];
        }
        
public object this[int i]
        {
            
get { return items[i]; }
            
set { this.items[i] = value; }
        }
        
#region ICollection Members

        
public int Count
        {
            
get { return items.Length; }
        }

        
public Iterator GetIterator()
        {
            
return new ListIterator(this);
        }

        
#endregion
    }
    
public class ListIterator : Iterator
    {
        
private int index = 0;
        
private ICollection list;
        
public ListIterator(ICollection list)
        {
            
this.list = list;
            index 
= 0;
        }
        
#region Iterator Members

        
public bool MoveNext()
        {
            
if (index + 1 > list.Count)
                
return false;
            
else
            { 
                index
++;
                
return true;
            }
        }

        
public object Current
        {
            
get { return list[index]; }
        }

        
#endregion
    }
    
/// 
    
/// 测试
    
/// 
    public class Program
    {
        
static void Main()
        {
            ICollection list 
= new List();
            Iterator iterator 
= list.GetIterator();
            
while (iterator.MoveNext())
            {
                
object current = iterator.Current;
            }
        }
}

系列文章导航:

走进Linq--Linq横空出世篇

走进Linq-辉煌的背后

走进Linq-Linq大观园

不能不说的C#特性-对象集合初始化器

不能不说的C#特性-匿名类型与隐式类型局部变量

不能不说的C#特性-扩展方法

不能不说的C#特性-匿名方法和Lambda表达式

不能不说的C#特性-迭代器(上)及一些研究过程中的副产品

不能不说的C#特性-迭代器(下),yield以及流的延迟计算

走进Linq-Linq to Objects(上)基础篇

走进Linq-Linq to Objects(下)实例篇

走进Linq-Linq to SQL感性认识篇

走进Linq-Linq to SQL How do I(1)

走进Linq-Linq to SQL How do I(2)

走进Linq-Linq to SQL How do I(3)

走进Linq-How do I(4)拾遗补零篇第一节

走进Linq-Linq to SQL源代码赏析 Table的获取过程

走进Linq-Linq to SQL源代码赏析之Provider的初始化

走进Linq-Linq to SQL源代码赏析,通过Linq to SQL看Linq


看看最后的测试,是不是不管具体的集合如何改变,遍历代码都非常稳定?而且扩展新的集合类也非常方便,只是添加代码不会修改原来的代码,符合开闭原则。当然,这么好的解决方案微软当然不会放过,现在C# 2.0里已经内置了对迭代器的支持,看看System.Collections, System.Collections.Generic命名空间,所有的集合都实现了这个接口:IEnumerable,这个接口还有泛型的版本。注意到这个接口只有一个方法:IEnumerator GetEnumerator();,IEnumerator就是迭代器的接口,相当于我的实例里面的Iterator,它也有泛型的版本。

那么现在在.NET里所有的集合类都可以这样访问了:

IEnumerator ienumerator = list.GetEnumerator();
while(ienumerator.MoveNext())
{
    
object current = ienumerator.Current;
}

系列文章导航:

走进Linq--Linq横空出世篇

走进Linq-辉煌的背后

走进Linq-Linq大观园

不能不说的C#特性-对象集合初始化器

不能不说的C#特性-匿名类型与隐式类型局部变量

不能不说的C#特性-扩展方法

不能不说的C#特性-匿名方法和Lambda表达式

不能不说的C#特性-迭代器(上)及一些研究过程中的副产品

不能不说的C#特性-迭代器(下),yield以及流的延迟计算

走进Linq-Linq to Objects(上)基础篇

走进Linq-Linq to Objects(下)实例篇

走进Linq-Linq to SQL感性认识篇

走进Linq-Linq to SQL How do I(1)

走进Linq-Linq to SQL How do I(2)

走进Linq-Linq to SQL How do I(3)

走进Linq-How do I(4)拾遗补零篇第一节

走进Linq-Linq to SQL源代码赏析 Table的获取过程

走进Linq-Linq to SQL源代码赏析之Provider的初始化

走进Linq-Linq to SQL源代码赏析,通过Linq to SQL看Linq


调用迭代器的MoveNext()方法,L_004e: brtrue.s L_0036 如果是true的话跳转,

L_0036: ldloc.2 
L_0037: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
L_003c: stloc.1 
L_003d: ldloc.1 
L_003e: callvirt instance string [mscorlib]System.Object::ToString()
L_0043: call void [mscorlib]System.Console::WriteLine(string)

it知识库不能不说的C#特性-迭代器(上)及一些研究过程中的副产品,转载需保留来源!

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。