c 迭代器 文件

2021-10-19 07:45:45 字數 3842 閱讀 6873

編寫的幾乎每個程式都需要迴圈訪問集合。 因此需要編寫**來檢查集合中的每一項。

還需建立迭代器方法,這些方法可為該類的元素生成迭代器(該物件遍歷容器,尤其是列表)。 這些方法可用於:

c# 語言提供了適用於這兩種方案的功能。 本文概述了這些功能。

列舉集合非常簡單:使用foreach關鍵字列舉集合,從而為集合中的每個元素執行一次嵌入語句:

c#複製

foreach (var item in collection)

就這麼簡單。 若要迴圈訪問集合中的所有內容,只需使用foreach語句。 但foreach語句並非完美無缺。 它依賴於 .net core 庫中定義的 2 個泛型介面,才能生成迴圈訪問集合所需的**:ienumerableienumerator。 下文對此機制進行了更詳細說明。

這 2 種介面還具備相應的非泛型介面:ienumerableienumerator。 泛型版本是新式**的首要選項。

借助 c# 語言的另乙個強大功能,能夠生成建立列舉源的方法。 這些方法稱為「迭代器方法」 。 迭代器方法用於定義請求時如何在序列中生成物件。 使用yield return上下文關鍵字定義迭代器方法。

可編寫此方法以生成從 0 到 9 的整數序列:

c#複製

public ienumerablegetsingledigitnumbers()

上方的**顯示了不同的yield return語句,以強調可在迭代器方法中使用多個離散yield return語句這一事實。 可以使用其他語言構造來簡化迭代器方法的**,這也是一貫的做法。 以下方法定義可生成完全相同的數字序列:

c#複製

public ienumerablegetsingledigitnumbers()

不必從中選擇乙個。 可根據需要提供盡可能多的yield return語句來滿足方法需求:

c#複製

public ienumerablegetsingledigitnumbers()

這是基本語法。 我們來看乙個需要編寫迭代器方法的真實示例。 假設你正在處理乙個 iot 專案,裝置感測器生成了大量資料流。 為了獲知資料,需要編寫乙個對每第 n 個資料元素進行取樣的方法。 通過以下小迭代器方法可實現此目的:

c#複製

public static ienumerablesample(this ienumerablesourcesequence, int interval)

}

迭代器方法有乙個重要限制:在同一方法中不能同時使用return語句和yield return語句。 不會編譯以下內容:

c#複製

public ienumerablegetsingledigitnumbers()

; return items;

}

此限制通常不是問題。 可以選擇在整個方法中使用yield return,或選擇將原始方法分成多個方法,一些使用return,另一些使用yield return

可略微修改一下最後乙個方法,使其可在任何位置使用yield return

c#複製

public ienumerablegetsingledigitnumbers()

; foreach (var item in items)

yield return item;

}

有時,正確的做法是將迭代器方法拆分成 2 個不同的方法。 乙個使用return,另乙個使用yield return。 考慮這樣一種情況:需要基於布林引數返回乙個空集合,或者返回前 5 個奇數。 可編寫類似以下 2 種方法的方法:

c#複製

public ienumerablegetsingledigitoddnumbers(bool getcollection)

private ienumerableiteratormethod()

}

看看上面的方法。 第 1 個方法使用標準return語句返回空集合,或返回第 2 個方法建立的迭代器。 第 2 個方法使用yield return語句建立請求的序列。

foreach語句可擴充套件為使用ienumerableienumerator介面的標準用語,以便迴圈訪問集合中的所有元素。 還可最大限度減少開發人員因未正確管理資源所造成的錯誤。

編譯器將第 1 個示例中顯示的foreach迴圈轉換為類似於此構造的內容:

c#複製

ienumeratorenumerator = collection.getenumerator();

while (enumerator.movenext())

上述構造表示由 c# 編譯器版本 5 及更高版本生成的**。 在版本 5 之前,item變數的範圍有所不同:

c#複製

// c# versions 1 through 4:

ienumeratorenumerator = collection.getenumerator();

int item = default(int);

while (enumerator.movenext())

此範圍更改的原因在於:較早行為可能導致難以診斷出有關 lambda 表示式的 bug。 若要詳細了解 lambda 表示式,請參閱 lambda 表示式。

編譯器生成的確切**更複雜一些,用於處理getenumerator()返回的物件實現idisposable的情況。 完整擴充套件生成的**更類似如下:

c#複製

} finally

}

列舉器的釋放方式取決於enumerator型別的特徵。 一般情況下,finally子句擴充套件為:

c#複製

finally

但是,如果enumerator的型別為已密封型別,並且不存在從型別enumeratoridisposable的隱式轉換,則finally子句擴充套件為乙個空白塊:

c#複製

finally

如果存在從型別enumeratoridisposable的隱式轉換,並且enumerator是不可為 null 的值型別,則finally子句擴充套件為:

c#複製

finally

幸運地是,無需記住所有這些細節。foreach語句會為你處理所有這些細微差別。 編譯器會為所有這些構造生成正確的**。

C 迭代器之 反向迭代器

反向迭代器 reverse iterator 是普通迭代器的介面卡,通過重新定義自增和自減操作,以達到按反序遍歷元素的目的。如果在標準演算法庫中用反向迭代器來代替普通的迭代器,那麼執行結果與正常情況下相反。除此之外,其用法與普通迭代器完全一樣,我們不作詳細討論。這裡主要討論的是反向迭代器的乙個很特殊...

C 迭代器 迭代器失效問題

問題描述 輸入乙個整數陣列,實現乙個函式來調整該陣列中數字的順序,使得所有的奇數字於陣列的前半部分,所有的偶數字於位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。這是劍指offer上的一道經典習題,我們首先可以想到的解決方案是 再建立乙個臨時陣列把偶數先存放起來,然後把臨時空間的...

C 迭代器(STL迭代器)iterator詳解

要訪問順序容器和關聯容器中的元素,需要通過 迭代器 iterator 進行,迭代器是乙個變數,相當於容器和操作容器的演算法之間的中介。迭代器可以指向容器中的某個元素,通過迭代器就可以讀寫它指向的元素。從這一點上看,迭代器和指標型別。迭代器按照定義方式分為以下四種 正向迭代器,定義方式 容器類名 it...