分享
 
 
 

C# 2.0 Specification(迭代器)(二)

王朝c#·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

22.4 yield 语句

yield语句用于迭代器块以产生一个枚举器对象值,或表明迭代的结束。

embedded-statement:(嵌入语句)

...

yield-statement(yield语句)

yield-statement:(yield 语句)

yield return expression ;

yield

break ;

为了确保和现存程序的兼容性,yield并不是一个保留字,并且 yield只有在紧邻return或

break关键词之前才具有特别的意义。而在其他上下文中,它可以被用作标识符。

yield语句所能出现的地方有几个限制,如下所述。

l yield语句出现在方法体、运算符体和访问器体之外时,将导致编译时错误。

l yield语句出现在匿名方法之内时,将导致编译时错误。

l yield语句出现在try语句的finally语句中时,将导致编译时错误。

l yield return 语句出现在包含catch子语句的任何try语句中任何位置时,将导致编译时错误。

如下示例展示了yield语句的一些有效和无效用法。

delegate IEnumerable<int> D();

IEnumerator<int> GetEnumerator() {

try {

yield return 1; // Ok

yield break; // Ok

}

finally {

yield return 2; // 错误, yield 在finally中

yield break; // 错误, yield 在 finally中

}

try {

yield return 3; // 错误, yield return 在try...catch中

yield break; // Ok

}

catch {

yield return 4; // 错误, yield return 在 try...catch中

yield break; // Ok

}

D d = delegate {

yield return 5; // 错误, yield 在匿名方法中

};

}

int MyMethod() {

yield return 1; // 错误, 迭代器块的错误返回类型

}

从yield return 语句中表达式类型到迭代器的产生类型(§22.1.3),必须存在隐式转换(§6.1)。

yield return 语句按如下方式执行。

l 在语句中给出的表达式将被计算(evaluate),隐式地转换到产生类型,并被赋给枚举器对象的Current属性。

l 迭代器块的执行将被挂起。如果yield return 语句在一个或多个try块中,与之关联的finally块此时将不会执行。

l 枚举器对象的MoveNext方法对调用方返回true,表明枚举器对象成功前进到下一个项。

对枚举器对象的MoveNext方法的下一次调用,重新从迭代器块挂起的地方开始执行。

yeld break 语句按如下方式执行。

l 如果yield break 语句被包含在一个或多个带有finally块的try块内,初始控制权将转移到最里面的try语句的finally块。当控制到达finally块的结束点后,控制将会转移到下一个最近的try语句的finally块。这个过程将会一直重复直到所有内部的try语句的finally块都被执行。

l 控制返回到迭代器块的调用方。这可能是由于枚举器对象的MoveNext方法或Dispose方法。

由于yield break语句无条件的转移控制到别处,所以yield break语句的结束点将永远不能到达。

22.4.1明确赋值

对于以yield return expr 形式的yield return 语句stmt

l 像stmt开始一样,在expr的开头变量v具有明确的赋值状态。

l 如果在expr的结束点v被明确赋值,那它在stmt的结束点也将被明确赋值;否则,在stmt结束点将不会被明确赋值。

22.5实现例子

本节以标准C#构件的形式描述了迭代器的可能实现。此处描述的实现基于与Microsoft C#编译器相同的原则,但这绝不是强制或唯一可能的实现。

如下Stack<T>类使用迭代器实现了GetEnumerator方法。该迭代器依序枚举了堆栈中从顶到底的元素。

using System;

using System.Collections;

using System.Collections.Generic;

class Stack<T>: IEnumerable<T>

{

T[] items;

int count;

public void Push(T item) {

if (items == null) {

items = new T[4];

}

else if (items.Length == count) {

T[] newItems = new T[count * 2];

Array.Copy(items, 0, newItems, 0, count);

items = newItems;

}

items[count++] = item;

}

public T Pop() {

T result = items[--count];

items[count] = T.default;

return result;

}

public IEnumerator<T> GetEnumerator() {

for (int i = count - 1; i >= 0; --i) yield items[i];

}

}

GetEnumerator方法可以被转换到编译器生成的枚举器类的实例,该类封装了迭代器块中的代码,如下所示。

class Stack<T>: IEnumerable<T>

{

...

public IEnumerator<T> GetEnumerator() {

return new __Enumerator1(this);

}

class __Enumerator1: IEnumerator<T>, IEnumerator

{

int __state;

T __current;

Stack<T> __this;

int i;

public __Enumerator1(Stack<T> __this) {

this.__this = __this;

}

public T Current {

get { return __current; }

}

object IEnumerator.Current {

get { return __current; }

}

public bool MoveNext() {

switch (__state) {

case 1: goto __state1;

case 2: goto __state2;

}

i = __this.count - 1;

__loop:

if (i < 0) goto __state2;

__current = __this.items[i];

__state = 1;

return true;

__state1:

--i;

goto __loop;

__state2:

__state = 2;

return false;

}

public void Dispose() {

__state = 2;

}

void IEnumerator.Reset() {

throw new NotSupportedException();

}

}

在先前的转换中,迭代器块之内的代码被转换成state machine,并被放置在枚举器类的MoveNext方法中。此外局部变量i被转换成枚举器对象的一个字段,因此在MoveNext的调用过程中可以持续存在。

下面的例子打印一个简单的从整数1到10的乘法表。该例子中FromTo方法返回一个可枚举对象,并且使用迭代器实现。

using System;

using System.Collections.Generic;

class Test

{

static IEnumerable<int> FromTo(int from, int to) {

while (from <= to) yield return from++;

}

static void Main() {

IEnumerable<int> e = FromTo(1, 10);

foreach (int x in e) {

foreach (int y in e) {

Console.Write("{0,3} ", x * y);

}

Console.WriteLine();

}

}

}

FromTo方法可被转换成编译器生成的可枚举类的实例,该类封装了迭代器块中的代码,如下所示。

using System;

using System.Threading;

using System.Collections;

using System.Collections.Generic;

class Test

{

...

static IEnumerable<int> FromTo(int from, int to) {

return new __Enumerable1(from, to);

}

class __Enumerable1:

IEnumerable<int>, IEnumerable,

IEnumerator<int>, IEnumerator

{

int __state;

int __current;

int __from;

int from;

int to;

int i;

public __Enumerable1(int __from, int to) {

this.__from = __from;

this.to = to;

}

public IEnumerator<int> GetEnumerator() {

__Enumerable1 result = this;

if (Interlocked.CompareExchange(ref __state, 1, 0) != 0) {

result = new __Enumerable1(__from, to);

result.__state = 1;

}

result.from = result.__from;

return result;

}

IEnumerator IEnumerable.GetEnumerator() {

return (IEnumerator)GetEnumerator();

}

public int Current {

get { return __current; }

}

object IEnumerator.Current {

get { return __current; }

}

public bool MoveNext() {

switch (__state) {

case 1:

if (from > to) goto case 2;

__current = from++;

__state = 1;

return true;

case 2:

__state = 2;

return false;

default:

throw new InvalidOperationException();

}

}

public void Dispose() {

__state = 2;

}

void IEnumerator.Reset() {

throw new NotSupportedException();

}

}

}

这个可枚举类实现了可枚举接口和枚举器接口,这使得它成为可枚举的或枚举器。当GetEnumerator方法被首次调用时,将返回可枚举对象自身。后续可枚举对象的GetEnumerator调用,如果有的话,都返回可枚举对象的拷贝。因此,每次返回的枚举器都有其自身的状态,改变一个枚举器将不会影响另一个。Interlocked.CompareExchange方法用于确保线程安全操作。

from和to参数被转换为可枚举类的字段。由于from在迭代器块内被修改,所以引入另一个__from字段来保存在每个枚举其中from的初始值。

如果当__state是0时MoveNext被调用,该方法将抛出InvalidOperationException异常。这将防止没有首次调用GetEnumerator,而将可枚举对象作为枚举器而使用的现象发生。

(C# 2.0 Specification 全文完)

吁....&^%终于敲完,该歇歇了,呵呵,眼睛冒火花**&&^%%...

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有