频 道 直 达 - 新闻 - 培训 - 软件 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 读书 - 博客 - BBS
51CTO.COM_中国最大的网络技术网站
找资料:

5.6.3 yield语句

作者: Christian Nagel等著 李铭 译 黄静 审校 出处:清华大学出版社  2007-12-14 13:05    砖    好    评论   进入论坛
阅读提示:《C#2005&.NET_3.0高级编程》(第5版)第五章介绍的是数组还有Array类在后台发挥作用。本文主要介绍的是yield语句。

5.6.3  yield语句

C# 1.0使用foreach语句可以轻松地迭代集合。在C# 1.0中,创建枚举器仍需要做大量的工作。C# 2.0添加了yield语句,以便于创建枚举器。

yield return语句返回集合的一个元素,并移动到下一个元素上。yield break可停止迭代。

下面的例子是用yield return语句实现一个简单集合的代码。类HelloCollection包含GetEnumerator()方法。该方法的实现代码包含两个yield return语句,它们分别返回字符串Hello和World。

using System;
using System.Collection;

namespace Wrox.ProCAharp.Arrays
{
  public class HelloCollection
  {
    public IEumerator GetEumerator()
    {
    yield return "Hello";
    yield return "World";
}
}
}

警告:
包含yield语句的方法或属性也称为迭代块。迭代块必须声明为返回IEnumerator或IEnumerable接口。这个块可以包含多个yield return语句或yield break语句,但不能包含return语句。

现在可以用foreach语句迭代集合了:

public class Program 
{
   HelloCollection helloCollection = new HelloCollection();
   foreach (string s in helloCollection)
{
      Console.WriteLine(s);
}
}
}

使用迭代块,编译器会生成一个yield 类型,其中包含一个状态机,如下面的代码所示。yield 类型执行IEnumerator和IDisposable接口的属性和方法。在下面的例子中,可以把yield 类型看作内部类Enumerator。外部类的GetEnumerator()方法实例化并返回一个新的yield 类型。在yield 类型中,变量state定义了迭代的当前位置,每次调用MoveNext()时,当前位置都会改变。MoveNext()封装了迭代块的代码,设置了current变量的值,使Current属性根据位置返回一个对象。

public class HelloCollection 
{
public IEnumerator GetEnumerator()
  {
    Enumerator enumerator = new Enumerator();
    return enumerator;
} 

public class Enumerator : IEnumerator, IDisposable
{
  private int state;
  private object current;

  public Enumerator(int state)
  {
    this.state = state;
}
bool System.Collections.IEnumerator.MoveNext()
{
  switch (state)
  {
     case 0:
       current = "Hello";
       state = 1;
               return true;
              case 1:
                current = "World";
                state = 2;
                return true;
              case 2:
                break;
           }
           return false;
        }
        void System.Collections.IEnumerator.Reset()
        {
          throw new NotSupportedException();
}

object System.Collections.IEnumerator.Current
{
          get
          {
          return current;
}
}
        void IDisposable.Dispose()
        {
}
} 
}


现在使用yield return语句,很容易实现允许以不同方式迭代集合的类。类MusicTitles可以用默认方式通过GetEnumerator()方法迭代标题,用Reverse()方法逆序迭代标题,用Subset()方法搜索子集:

public class MusicTitles
{
  string[] names = {
         "Tubular Bells", "Hergest Ridge",
         "Ommadawn", "Platinum");
  public IEnumerator GetEnumerator()
  {
     for (int i = 0; i < 4; i++)
     {
     yield return names[i];
}
}
  public IEnumerable Reverse()
  {
     for (int i = 3; i >= 0; i–)
     {
             yield return names[i];
}
}
public IEnumerable Subset( int index, int length)
{
        for (int i = index; i < index + length; i++)
        {
            yield return names[i];
}
}
}

迭代字符串数组的客户代码先使用GetEnumerator()方法,该方法不必在代码中编写,因为这是默认使用的方法。然后逆序迭代标题,最后将索引和要迭代的元素个数传送给Subset()方法,来迭代子集:

MusicTitles titles = new MusicTitles();
foreach(string title in titles)
{
  ConsoleWriteLine(title);
}
ConsoleWriteLine();

ConsoleWriteLine("reverse");
foreach(string title in titles.Reverse())
{
  ConsoleWriteLine(title);
}
ConsoleWriteLine();

ConsoleWriteLine("subset");
foreach(string title in titles.Subset(2, 2))
{
  ConsoleWriteLine(title);
}

使用yield语句还可以完成更复杂的任务,例如从yield return中返回枚举器。

在TicTacToe游戏中有9个域,玩家轮流在这些域中放置“十”字或一个圆。这些移动操作由GameMoves类模拟。方法Cross()和Circle()是创建迭代类型的迭代块。变量cross和circle在GameMoves类的构造函数中设置为Cross()和Circle()方法。这些域不设置为调用的方法,而是设置为用迭代块定义的迭代类型。在Cross()迭代块中,将移动操作的信息写到控制台上,并递增移动次数。如果移动次数大于9,就用yield break停止迭代;否则,就在每次迭代中返回yield类型cross的枚举对象。Circle()迭代块非常类似于Cross()迭代块,只是它在每次迭代中返回circle迭代类型。

public calss GameMoves
{
  private IEnumerator cross;
  private IEnumerator circle;

  public GameMoves()
  {
    cross = Cross();
    circle = Circle();
}

  private int move = 0;

  public IEnumerator Cross()
  {
     while (true)
     {
       Console.WriteLine("Cross, move {0}", move);
       move++;
       if (move > 9)
         yield break;
       yield return circle;
     }
}
 
  public IEnumerator Circle()
  {
     while (true)
     {
       Console.WriteLine("Circle, move {0}", move);
       move++;
       if (move > 9)
         yield break;
       yield return cross;
     }
}  
}

在客户程序中,可以以如下方式使用GameMoves类。将枚举器设置为由game.Cross()返回的枚举器类型,以设置第一次移动。enumerator.MoveNext调用以迭代块定义的一次迭代,返回另一个枚举器。返回的值可以用Current属性访问,并设置为enumerator变量,用于下一次循环:

GameMoves game = new GameMoves();
IEnumerator enumerator = game.Cross();
while (enumerator.MoveNext())
{
  enumerator = (IEnumerator) enumerator.Current;
}

这个程序的输出会显示交替移动的情况,直到最后一次移动:
Cross, move 0
Circle, move 1
Cross, move 2
Circle, move 3
Cross, move 4
Circle, move 5
Cross, move 6
Circle, move 7
Cross, move 8

【责任编辑:董书 TEL:(010)68476606】

回书目   上一节   下一节
专题
C#实用基础教程
专题:ASP.NET 2.0基础开发指南
.NET移动与嵌入式技术专题
.NET Framework新手入门专题
VS.NET实用开发专题
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 最 大 的 网 络 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
浏览器的战国时代
浏览器的战国时代
ARP攻击防范与解决方案
ARP攻击防范与解决方案
NAC安全访问控制
NAC安全访问控制
· NAC安全访问控制
· 网络布线测试仪器
· Windows Server 2008专..
· Windows远程桌面应用
· 网络故障排除宝典
· 运营商封堵ADSL共享 中..
· 解析35岁技术人的价值..
· 世纪枭雄比尔盖茨的王..
· 主流品牌防火墙配置
· ASP.NET开发教程
· 超级计算机TOP500专题
· Vista SP1对决XP SP3
· SQL Server 2008/2005..
· 程序员如何成长?
· C#技术开发指南
· 虚拟化技术还有点“虚”
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
SOA 面向服务架构
SOA 面向服务架构
· SOA 面向服务架构
· SQL Server 2008/2005..
· Apache技术专题
· 三层交换技术专题
· SQL Server入门到精通
· Windows远程桌面应用
· C#技术开发指南
· Apache技术专题
· Windows集群服务应用
· C#技术开发指南
· 国际文档格式标准开战
· 路由器设置与口令恢复
· Linux 集群技术专题
· PHP开发应用手册
· SOA 面向服务架构
· 企业数据恢复指南
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
SQL Server入门到精通
SQL Server入门到精通
· SQL Server入门到精通
· SQL Server 2008/2005..
· SOA 面向服务架构
· Apache技术专题
· C#技术开发指南
· 三层交换技术专题
· Apache技术专题
· C#技术开发指南
· Windows远程桌面应用
· 企业数据恢复指南
· Windows集群服务应用
· 路由器设置与口令恢复
· Linux 集群技术专题
· SOA 面向服务架构
· 了解统一威胁管理(UTM)..
· 反垃圾邮件技术应用