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

22 迭代器

22.1 迭代器块

迭代器块就是产生值的有序序列的语句块。迭代器块通过一个或多个 yield 语句区别于常规语句块。

l yield return 语句产生迭代的下一个值。

l yield break 语句指明迭代完成。

迭代器块可以被用作一个方法体( method-body )、运算符体( operator-body )、访问器体( accessor-body ) , 前提是对应函数成员的返回类型是枚举器 (enumerator) 接口之一或者可枚举 (enumerable) 接口之一。

迭代器块在 C# 语法中不什么独特的元素。它们在几个方面受到限制,并且主要的作用在函数成员声明的语义上,但它们在语法上只是语句块而已。

当一个函数成员使用迭代器块实现时,对于正式参数列表指定任何 ref 或 out 参数将导致编译时错误。

return 语句出现在迭代器块中将导致编译时错误(但 yield return 语句是允许的)。

在迭代器块中包含不安全上下文 (§18.1) 将导致编译时错误。即使是当迭代器声明内嵌在不安全上下文中,迭代器块也总是定义为一个安全上下文。

22.1.1 枚举器接口

** 枚举器接口 (enumerator interface) ** 是 System.Collections.IEnumerator 接口以及 System.Collections.Generic.IEnumerator

  1<t> 的所有实例。在本章,这些接口将相应地作为  IEnumerator  和  IEnumerator<t> 而引用。 
  2
  3###  22.1.2  可枚举接口 
  4
  5** 可枚举接口(  enumerable interface  ** ** )  ** 是  System.Collections.IEnumerable  接口和  System.Collections.Generic.IEnumerable<t> 的所有实例。在本章,这些接口将相应地作为  IEnumerable  和  IEnumerable<t> 而被引用。 
  6
  7  
  8
  9
 10###  22.1.3Yield  类型 
 11
 12迭代器块生成具有相同类型的所有值的序列。给类型被称为迭代器块的  ** yield  ** ** 类型(  yield type  ** ** )  ** 。 
 13
 14l  迭代器块的  yield  类型通常用于实现返回  IEnumerator  或  IEnumerable  是对象的函数成员。 
 15
 16l  迭代器块的  yield  类型通常用于实现返回  IEnumerator<t> 或  IEnumerable<t> 是  T  的函数成员。 
 17
 18###  22.1.4 this  访问 
 19
 20在类的实例成员的迭代器块内,  this  表达式被归类为值。该值的类型就是类类型,在这个类型可以采用这种用法,这个值就是成员被调用时的对象的引用。 
 21
 22在结构的实例成员的迭代器块内,  this  表达时被归类作为一个变量。该变量的类型就是结构类型,在这个结构中它可以采用这种用法。该变量表示一个成员被调用时的对应结构的一个拷贝。在结构实例成员的迭代器块内,  this  变量的行为就好像是结构类型的一个值参数。 
 23
 24##  22.2  枚举对象 
 25
 26当返回枚举器接口类型的函数成员使用迭代器块实现时,调用函数成员并不会立即执行迭代器块中的代码。相反,枚举器对象(  enumerator object  )将被创建和返回。该对象封装了在迭代器块中指定的代码,当枚举器对象的  MoveNext  方法被调用时,迭代器块中的代码就会执行。枚举器对象有如下的特征。 
 27
 28l  它实现了  IEnumerator  和  IEnumerator<t> ,  T  是迭代器块的  yield  类型  (  产生类型  )  。 
 29
 30l  它实现了  System.IDisposable  。 
 31
 32  
 33
 34
 35l  它被使用实参值(如果有的话)的拷贝而初始化,而实例值将被传递给函数成员。 
 36
 37l  它有四个潜在的状态  before  、  running  、  suspended  和  after  ,并且它在  before  状态之前被初始化。 
 38
 39枚举器对象通常是一个编译器生成的枚举器类实例,它封装了迭代器语句块中的代码,并且实现了枚举器接口,但其它实现方法也是可以的。如果一个枚举器类是由编译器生成的,这个类将会是内嵌的,在包含函数成员的类中,类将具有私有可访问性,并且该类具有一个保留为编译器所用的名字  (§2.4.2)  。 
 40
 41枚举器对象可以实现比在此指定的更多接口。 
 42
 43随后几节描述了由  IEnumerable  和  IEnumerable<t> 接口实现的  MoveNext  、  Current  、和  Dispose  成员的确切行为,这两个接口由枚举对象提供。 
 44
 45请注意,枚举器对象并不支持  IEnumerator.Reset  方法。调用该方法将会抛出  System.NotSupportedException  异常。 
 46
 47##  22.2.1MoveNext  方法 
 48
 49枚举器对象的  MoveNext  方法封装了迭代器块的代码。调用  MoveNext  方法将执行迭代器内的代码,并将枚举对象的  Current  属性设置为合适的值。由  MoveNext  方法执行的精确动作,取决于当  MoveNext  方法被调用时枚举器对象的状态。 
 50
 51l  如果枚举器对象状态是  before  ,调用  MoveNext 
 52
 53n  将把状态改为  running  。 
 54
 55n  将把迭代器块的参数(包括  this  )初始化为,当枚举器对象被初始化而保存的实参值和实例值。 
 56
 57n  从开始执行迭代器块直到执行被中断(如下面所描述的)。 
 58
 59l  如果枚举器对象的状态是  running  ,调用  MoveNext  的结果是未指定的。 
 60
 61l  如果枚举器对象的状态是  suspended  ,调用  MoveNext 
 62
 63n  将把状态改为  running  。 
 64
 65  
 66
 67
 68l  恢复所有局部变量和参数(包括  this  )的值为迭代器最后一次挂起(  suspended  )时执行状态的值。请注意,由这些变量所引用的任何对象的内容,都可能因为前一次对  MoveNext  的调用而改变。 
 69
 70n  在引发执行挂起的  yield return  语句之后重新开始执行迭代器块,并且这个状态会继续直到执行被中断(如下所描述)。 
 71
 72l  如果枚举器对象的状态是  after  ,那么调用  MoveNext  将返回  false  。 
 73
 74当  MoveNext  执行迭代器块时,有四种方法可以中断执行:通过一个  yield return  语句,通过一个  yield break  语句,到达迭代器块的结束点,以及一个异常被抛出,并被传播到迭代器块之外。 
 75
 76l  当遇到一个  yield return  语句时  (§  22.4  )  ,将会发生如下情况 
 77
 78n  在该语句中被给定的表达式将被计算,隐式地转换到产生类型(  yield type  )  ,  并被赋值给枚举对象的  Current  属性。 
 79
 80n  迭代器体的执行将被挂起。所有局部变量的值和参数(包括  this  )被保存,该  yield return  语句的位置也被保存。如果  yield return  语句在一个或多个  try  块之内,与之关联的  finally  块在此时将不会执行。 
 81
 82n  枚举器对象的状态被改为  suspended  。 
 83
 84n  MoveNext  方法对调用方返回  true  ,表明迭代器成功前进到下一个值。 
 85
 86l  当遇到  yield break  语句时,将会发生如下情况 
 87
 88n  如果  yield break  语句在一个或多个  try  块之内,与之关联的  finally  语句将被执行。 
 89
 90n  枚举器对象的状态被改为  after  。 
 91
 92n  MoveNext  方法对调用方返回  false  ,表明迭代已经完成。 
 93
 94l  当遇到迭代器块的结束点时,将会发生如下情况。 
 95
 96n  枚举器对象的状态被改为  after  。 
 97
 98n  MoveNext  方法对调用方返回  false  ,表明迭代已经完成。 
 99
100  
101
102
103l  当一个异常被抛出并被传播到迭代器块之外时,将会发生如下情况。 
104
105n  在迭代器块之内将会由于异常传播  (exception propagation)  而执行合适的  finally  块。 
106
107n  枚举器对象的状态被改为  after  。 
108
109n  对于  MoveNext  方法的调用方来说,异常传播将会继续。 
110
111###  22.2.2 Current  属性 
112
113枚举器对象的  Current  属性受到迭代器块的  yield return  语句的影响。 
114
115当枚举器对象处于  suspended  状态时,  Current  的值就是最后一次调用  MoveNext  时被设置的值。当枚举器对象处于  before  、  running  或  after  状态时,访问  Current  的所得结果是未指定的。 
116
117对于一个具有非  object  类型的  yield  类型迭代器块,通过枚举器对象的  IEnumerable  实现访问  Current  所得实现,对应于通过枚举器对象的  IEnumerator<t> 访问  Current  所得实现,并将结果转换到  object  类型。 
118
119###  22.2.3 Dispose  方法 
120
121Dispose  方法通过将枚举器对象的状态置为  after  ,以清理迭代结果。 
122
123l  如果枚举器对象的状态是  before  ,调用  Dispose  将改变其状态为  after  。 
124
125l  如果枚举器对象的状态是  running  ,调用  Dispose  的结果是为指定的。 
126
127l  如果枚举器对象的状态是  suspended  ,调用  Dispose  将 
128
129n  改变其状态为  running  。 
130
131n  执行  finally  块,就好像最后执行的  yield return  语句是一个  yield break  语句。如果这里引发一个异常被抛出并传播到迭代器体之外,枚举器对象的状态将被置为  after  ,并且该异常将被传播给  Dispose  方法的调用方。 
132
133n  改变其状态为  after  。 
134
135l  如果枚举器对象的状态为  after  ,调用  Dispose  没有效果。 
136
137**   
138**
139
140##  22.3  可枚举对象 
141
142当返回一个可枚举接口类型的函数成员使用迭代器块实现时,调用函数成员不会立即执行迭代器块代码。相反,一个 **可枚举对象(** ** enumerable object  ** ** )  ** 将被创建并返回。可枚举对象的  GetEnumerator  方法返回一个枚举器对象,它封装了在迭代器块中指定的代码,当枚举器对象的  MoveNext  方法被调用时,将触发迭代器块代码的执行。可枚举对象具有如下特征。 
143
144l  它实现了  IEnumerable  和  IEnumerable<t> 接口,这里  T  是迭代器块的产生类型(  yield type  )。 
145
146l  它使用实参值的拷贝进行初始化(如果有的话),并将实例值传递给函数成员。 
147
148可枚对象通常是一个由编译器生成的可枚举类的实例,该类封装了迭代器块的代码,并实现了可枚举接口,但其他实现方法也是可以的。如果可枚举类由编译器生成,该类将内嵌在包含函数成员的类中,并具有私有可访问性,以及一个为编译器所保留使用的名字  (§2.4.2)  。 
149
150可枚对象可以实现比在此说明的更多接口。特别的是,可枚举对象也可以实现  IEnumerator  和  IEnumerator<t> 接口,这使得它既可以作为一个可枚举对象又可作为枚举器对象。在那个实现类型中,对可枚举对象的  GetEnumerator  方法的首次调用,将返回可枚举对象自身。对于</t></t></t></t></t></t></t></t></t></t></t>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus