国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

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

2024-07-21 02:20:07
字體:
來源:轉載
供稿:網友
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 全文完)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 安龙县| 沈阳市| 昌乐县| 廉江市| 鹿邑县| 彭州市| 甘南县| 红桥区| 黄龙县| 青田县| 克东县| 桦甸市| 囊谦县| 葵青区| 金华市| 兴宁市| 元谋县| 日土县| 邵阳市| 四会市| 南靖县| 甘泉县| 余姚市| 四会市| 九台市| 都江堰市| 兴文县| 讷河市| 长岭县| 南充市| 积石山| 闵行区| 阿图什市| 融水| 任丘市| 疏勒县| 苏尼特右旗| 太谷县| 韶关市| 镇原县| 攀枝花市|