• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > C#特性-迭代器(上)及一些研究过程中的副产品

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

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c#迭代器,c#迭代器模式,c#迭代法,c#迭代器用法,c#迭代器是什么等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

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

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

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

提供一种一致的方式访问集合对象中的元素,而无需暴露集合对象的内部表示。
比如现在有这样一个需求,遍历集合内的元素,然后输出,但是并不限定集合是什么类型的集合,也就是未来集合可能发生改变。

思考:

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

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

/// <summary>
/// 集合的接口
/// </summary>
  public interface ICollection
  {
    int Count { get; }
    /// <summary>
    /// 获取迭代器
    /// </summary>
    /// <returns>迭代器</returns>
    Iterator GetIterator();
  }
  /// <summary>
  /// 迭代器接口
  /// </summary>
  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
  }
  /// <summary>
  /// 测试
  /// </summary>
  public class Program
  {
    static void Main()
    {
      ICollection list = new List();
      Iterator iterator = list.GetIterator();
      while (iterator.MoveNext())
      {
        object current = iterator.Current;
      }
    }
}
</div>

看看最后的测试,是不是不管具体的集合如何改变,遍历代码都非常稳定?而且扩展新的集合类也非常方便,只是添加代码不会修改原来的代码,符合开闭原则。当然,这么好的解决方案微软当然不会放过,现在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;
}
</div>

但是这样访问也太麻烦了,所以C#里出现了foreach关键字,我们来看看foreach背后发生了什么?假如有如下的代码:

public static void Main()
{      
      ArrayList list = new ArrayList();
      list.Add(1);
      list.Add(2);
      list.Add(3);
      foreach (object item in list)
      {
        Console.WriteLine(item.ToString());
      }
}
</div>

下面是它对应的IL代码:

.method private hidebysig static void Main() cil managed
{
  .entrypoint
  .maxstack 2
  .locals init (
    [0] class [mscorlib]System.Collections.ArrayList list,
    [1] object item,
    [2] class [mscorlib]System.Collections.IEnumerator CS$5$0000,
    [3] class [mscorlib]System.IDisposable CS$0$0001)
  L_0000: newobj instance void [mscorlib]System.Collections.ArrayList::.ctor()
  L_0005: stloc.0 
  L_0006: ldloc.0 
  L_0007: ldc.i4.1 
  L_0008: box int32
  L_000d: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
  L_0012: pop 
  L_0013: ldloc.0 
  L_0014: ldc.i4.2 
  L_0015: box int32
  L_001a: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
  L_001f: pop 
  L_0020: ldloc.0 
  L_0021: ldc.i4.3 
  L_0022: box int32
  L_0027: callvirt instance int32 [mscorlib]System.Collections.ArrayList::Add(object)
  L_002c: pop 
  L_002d: ldloc.0 
  L_002e: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
  L_0033: stloc.2 
  L_0034: br.s L_0048
  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)
  L_0048: ldloc.2 
  L_0049: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
  L_004e: brtrue.s L_0036
  L_0050: leave.s L_0063
  L_0052: ldloc.2 
  L_0053: isinst [mscorlib]System.IDisposable
  L_0058: stloc.3 
  L_0059: ldloc.3 
  L_005a: brfalse.s L_0062
  L_005c: ldloc.3 
  L_005d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
  L_0062: endfinally 
  L_0063: call string [mscorlib]System.Console::ReadLine()
  L_0068: pop 
  L_0069: ret 
  .try L_0034 to L_0052 finally handler L_0052 to L_0063
}
</div>

从.locals init 那里可以看出编译器为我们添加了两个局部变量,一个就是迭代器。

L_002d: ldloc.0
L_002e: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.ArrayList::GetEnumerator()
L_0033: stloc.2
</div>

这三行代码告诉我们,调用list的GetEnumerator()方法,获取迭代器实例将其赋值给编译器为我们添加的那个迭代器局部变量,接着是L_0034: br.s L_0048,
br.s这个指令是强制跳转,我们接着看

L_0048: ldloc.2
L_0049: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
</div>

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

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

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

相关文章

  • 2017-05-28在c#中把字符串转为变量名并获取变量值的小例子
  • 2017-05-28C#动态webservice调用接口
  • 2017-05-28C#微信开发之微信公众号标签管理功能
  • 2017-05-28Json操作库DynamicJson使用指南
  • 2017-05-28C#中数组初始化、反转和排序用法实例
  • 2017-05-28c#典型工厂化实现实例
  • 2017-05-28C#接口interface用法实例
  • 2017-05-28在Parallel中使用DbSet.Add()发现的一系列多线程问题和解决思路详解
  • 2017-05-28C#学习笔记- 浅谈数组复制,排序,取段,元组
  • 2017-05-28C#字符串使用密钥进行加解密

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 解析StreamReader与文件乱码问题的解决方法
    • C# 生成随机数的代码
    • 基于C#中XmlWriter写入Xml的深入分析
    • c#求两个数中最大值的方法
    • C#使用foreach遍历哈希表(hashtable)的方法
    • C#中获取、生成随机数的三种方法
    • C#使用有道ip地址查询接口方法实例详解
    • C#微信开发之获取接口调用凭据
    • richtextbox控件插入链接代码分享
    • 史上最简洁C# 生成条形码图片思路及示例分享

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有