首頁 >後端開發 >C#.Net教程 >C# 2.0 Specification(迭代器)(一)

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

黄舟
黄舟原創
2017-01-03 12:00:251440瀏覽

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)[/b]是System.Collections.IEnumerator介面以及System.Collections.Generic.IEnumerator的所有實例。在本章,這些介面將相應地作為IEnumerator和IEnumerator而引用。

22.1.2可枚舉介面

可枚舉介面(enumerable interface[/b])[/b]是System.Collections.IEnumerable介面和System.Collections.Generic.IEnumerable的所有實例。在本章,這些介面將會相應地作為IEnumerable和IEnumerable而被引用。

22.1.3Yield 類型

迭代器區塊產生具有相同類型的所有值的序列。給型別被稱為迭代器區塊的yield[/b]型別(yield type[/b])[/b]。
l 迭代器區塊的yield類型通常用於實作傳回IEnumerator或IEnumerable是物件的函數成員。
l 迭代器區塊的yield類型通常用於實作傳回IEnumerator或IEnumerable是T的函數成員。

22.1.4 this 存取

在類別的實例成員的迭代器區塊內,this表達式被歸類為值。該值的類型就是類別類型,在這個類型可以採用這種用法,這個值就是成員被呼叫時的物件的參考。
在結構的實例成員的迭代器區塊內,this表達時被歸類為一個變數。該變數的類型就是結構類型,在這個結構中它可以採用這種用法。此變數表示一個成員被呼叫時的對應結構的一個拷貝。在結構實例成員的迭代器區塊內,this變數的行為就好像是結構類型的一個值參數。

22.2枚舉物件

當傳回枚舉器介面類型的函數成員使用迭代器區塊實作時,呼叫函數成員並不會立即執行迭代器區塊中的程式碼。相反,枚舉器物件(enumerator object)將被建立和傳回。此物件封裝了在迭代器區塊中指定的程式碼,當枚舉器物件的MoveNext方法被呼叫時,迭代器區塊中的程式碼就會執行。枚舉器物件有如下的特徵。
l 它實作了IEnumerator和IEnumerator,T是迭代器區塊的yield型別(產生型別)。
l 它實作了System.IDisposable。



l 它被使用實參值(如果有的話)的拷貝而初始化,而實例值將被傳遞給函數成員。
l 它有四個潛在的狀態before、running、suspended和after,並且它在before狀態之前​​被初始化。

枚舉器物件通常是一個編譯器產生的枚舉器類別實例,它封裝了迭代器語句區塊中的程式碼,並且實作了枚舉器接口,但其它實作方法也是可以的。如果一個枚舉器類別是由編譯器產生的,這個類別將會是內嵌的,在包含函數成員的類別中,類別將具有私有可訪問性,並且該類別具有一個保留為編譯器所用的名字(§2.4.2)。
枚舉器物件可以實現比在此指定的更多介面。
隨後幾節描述了由IEnumerable和IEnumerable介面實現的MoveNext、Current、和Dispose成員的確切行為,這兩個介面由枚舉物件提供。
請注意,枚舉器物件並不支援IEnumerator.Reset方法。呼叫該方法將會拋出System.NotSupportedException異常。

22.2.1MoveNext方法

枚舉器物件的MoveNext方法封裝了迭代器區塊的程式碼。呼叫MoveNext方法將執行迭代器內的程式碼,並將枚舉物件的Current屬性設為適當的值。由MoveNext方法執行的精確動作,取決於當MoveNext方法被呼叫時枚舉器物件的狀態。
l 如果枚舉器物件狀態是before,呼叫MoveNext
n 將把狀態改為running。
n 將把迭代器區塊的參數(包括this)初始化為,當枚舉器物件被初始化而保存的實參值和實例值。
n 從開始執行迭代器區塊直到執行中斷(如下面所描述的)。
l 如果枚舉器物件的狀態是running,呼叫MoveNext的結果是未指定的。
l 如果枚舉器物件的狀態是suspended,呼叫MoveNext
n 將把狀態改為running。


l 恢復所有局部變數和參數(包括this)的值為迭代器最後一次掛起(suspended)時執行狀態的值。請注意,由這些變數所引用的任何物件的內容,都可能因為前一次對MoveNext的呼叫而改變。
n 在引發執行暫停的yield return 語句之後重新開始執行迭代器區塊,而這個狀態會繼續直到執行被中斷(如下所描述)。
l 如果枚舉器物件的狀態是after,那麼呼叫MoveNext將會傳回false。
當MoveNext執行迭代器區塊時,有四種方法可以中斷執行:透過一個yield return 語句,透過一個yield break語句,到達迭代器區塊的結束點,以及一個異常被拋出,並被傳播到迭代器塊之外。
l 當遇到一個yield return 語句時(§22.4),將會發生如下情況
n 在該語句中被給定的表達式將被計算,隱式地轉換到產生類型(yield type),並被賦值給枚舉物件的Current屬性。
n 迭代器體的執行將被掛起。所有局部變數的值和參數(包括this)被保存,該yield return 語句的位置也被保存。如果yield return 語句在一個或多個try區塊之內,與之關聯的finally區塊在此時將不會執行。
n 枚舉器物件的狀態改為suspended。
n MoveNext方法對呼叫方傳回true,表示迭代器成功前進到下一個值。
l 當遇到yield break 語句時,將會發生如下情況
n 如果yield break 語句在一個或多個try區塊之內,與之關聯的finally語句將被執行。
n 枚舉器物件的狀態改為after。
n MoveNext方法對呼叫方傳回false,表示迭代已經完成。
l 當遇到迭代器區塊的結束點時,將會發生如下情況。
n 枚舉器物件的狀態改為after。
n MoveNext方法對呼叫方傳回false,表示迭代已經完成。


l 當一個異常被拋出並被傳播到迭代器塊之外時,將會發生如下情況。
n 在迭代器區塊之內將會因為異常傳播(exception propagation)而執行合適的finally區塊。
n 枚舉器物件的狀態改為after。
n 對於MoveNext方法的呼叫方來說,異常傳播將會繼續。

22.2.2 Current屬性

枚舉器物件的Current屬性受到迭代器區塊的yield return 語句的影響。
當枚舉器物件處於suspended狀態時,Current的值就是最後一次呼叫MoveNext時被設定的值。當枚舉器物件處於before、running或after狀態時,存取Current的所得結果是未指定的。
對於一個具有非object類型的yield 類型迭代器區塊,透過枚舉器物件的IEnumerable實現存取Current所得實現,對應於透過枚舉器物件的IEnumerator存取Current所得實現,並將結果轉換為object類型。

22.2.3 Dispose方法

Dispose方法透過將枚舉器物件的狀態置為after,以清理迭代結果。
l 如果枚舉器物件的狀態是before,呼叫Dispose將改變其狀態為after。
l 如果枚舉器物件的狀態是running,呼叫Dispose的結果是為指定的。
l 如果枚舉器物件的狀態是suspended,呼叫Dispose將
n 改變其狀態為running。
n 執行finally區塊,就好像最後執行的yield return語句是一個yield break語句。如果這裡引發一個異常被拋出並傳播到迭代器體之外,枚舉器物件的狀態將被置為after,並且該異常將被傳播給Dispose方法的呼叫方。
n 改變其狀態為after。
l 如果枚舉器物件的狀態為after,呼叫Dispose沒有效果。

22.3可枚舉物件

當傳回一個可枚舉介面類型的函數成員使用迭代器區塊實作時,呼叫函數成員不會立即執行迭代器區塊程式碼。相反,一個可枚舉物件([/b]enumerable object[/b])[/b]將被建立並傳回。可枚舉物件的GetEnumerator方法傳回一個枚舉器對象,它封裝了在迭代器區塊中指定的程式碼,當枚舉器物件的MoveNext方法被呼叫時,將觸發迭代器區塊程式碼的執行。可枚舉物件具有下列特徵。
l 它實作了IEnumerable和IEnumerable接口,這裡T是迭代器區塊的產生類型(yield type)。
l 它使用實參值的拷貝進行初始化(如果有的話),並將實例值傳遞給函數成員。

可枚物件通常是一個由編譯器產生的可枚舉類別的實例,該類別封裝了迭代器區塊的程式碼,並實現了可枚舉接口,但其他實作方法也是可以的。如果可枚舉類別由編譯器生成,該類別將內嵌在包含函數成員的類別中,並具有私有可存取性,以及一個為編譯器所保留使用的名字(§2.4.2)。
可枚物件可以實現比在此說明的更多介面。特別的是,可枚舉物件也可以實現IEnumerator和IEnumerator接口,這使得它既可以作為一個可枚舉物件又可作為枚舉器物件。在那個實作類型中,可枚舉物件的GetEnumerator方法的首次調用,將返回可枚舉物件本身。對於該可枚舉物件的GetEnumerator方法的後續調用,如果有的話,將會傳回可列舉物件的一個拷貝。因此,每次返回的枚舉器將有它自己的狀態,並且在一個枚舉器中所做的改變不會影響另一個枚舉器。

22.3.1 GetEnumerator方法

可枚舉物件提供了IEnumerable和IEnumerable介面的GetEnumerator方法的一個實作。這兩個GetEnumerator方法共享一個公共實現,它是用來得到並傳回一個有效的枚舉器物件。
枚舉器物件使用實參值進行初始化,當可枚舉物件被初始化時其實例值將被保存,另一方面,枚舉器物件函數將如§22.2所描述。
(To be continued)

以上就是C# 2.0 Specification(迭代器)(一)的內容,更多相關內容請關注PHP中文網(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn