植髮婉之c#迭代器
編寫的幾乎每個程式都需要迴圈訪問集合。 因此需要編寫**來檢查集合中的每一項。
還需建立迭代器方法,這些方法可為該類的元素生成迭代器(該物件遍歷容器,尤其是列表)。 這些方法可用於:
c# 語言提供了適用於這兩種方案的功能。 本文概述了這些功能。
列舉集合非常簡單:使用foreach
關鍵字列舉集合,從而為集合中的每個元素執行一次嵌入語句:
foreach (var item in collection)
就這麼簡單。 若要迴圈訪問集合中的所有內容,只需使用foreach
語句。 但foreach
語句並非完美無缺。 它依賴於 .net core 庫中定義的 2 個泛型介面,才能生成迴圈訪問集合所需的**:ienumerable
和ienumerator
。 下文對此機制進行了更詳細說明。
這 2 種介面還具備相應的非泛型介面:ienumerable
和ienumerator
。 泛型版本是新式**的首要選項。
借助 c# 語言的另乙個強大功能,能夠生成建立列舉源的方法。 這些方法稱為「迭代器方法」 。 迭代器方法用於定義請求時如何在序列中生成物件。 使用yield return
上下文關鍵字定義迭代器方法。
可編寫此方法以生成從 0 到 9 的整數序列:
getsingledigitnumbers()
">public ienumerable getsingledigitnumbers()
上方的**顯示了不同的yield return
語句,以強調可在迭代器方法中使用多個離散yield return
語句這一事實。 可以使用其他語言構造來簡化迭代器方法的**,這也是一貫的做法。 以下方法定義可生成完全相同的數字序列:
getsingledigitnumbers()
">public ienumerable getsingledigitnumbers()
不必從中選擇乙個。 可根據需要提供盡可能多的yield return
語句來滿足方法需求:
getsingledigitnumbers()
">public ienumerable getsingledigitnumbers()
這是基本語法。 我們來看乙個需要編寫迭代器方法的真實示例。 假設你正在處理乙個 iot 專案,裝置感測器生成了大量資料流。 為了獲知資料,需要編寫乙個對每第 n 個資料元素進行取樣的方法。 通過以下小迭代器方法可實現此目的:
sample(this ienumerablesourcesequence, int interval)
}">public static ienumerablesample(this ienumerablesourcesequence, int interval)
}
迭代器方法有乙個重要限制:在同一方法中不能同時使用return
語句和yield return
語句。 不會編譯以下內容:
getsingledigitnumbers()
; return items;
}">public ienumerable getsingledigitnumbers()
; return items;
}
此限制通常不是問題。 可以選擇在整個方法中使用yield return
,或選擇將原始方法分成多個方法,一些使用return
,另一些使用yield return
。
可略微修改一下最後乙個方法,使其可在任何位置使用yield return
:
getsingledigitnumbers()
; foreach (var item in items)
yield return item;
}">public ienumerable getsingledigitnumbers()
; foreach (var item in items)
yield return item;
}
有時,正確的做法是將迭代器方法拆分成 2 個不同的方法。 乙個使用return
,另乙個使用yield return
。 考慮這樣一種情況:需要基於布林引數返回乙個空集合,或者返回前 5 個奇數。 可編寫類似以下 2 種方法的方法:
getsingledigitoddnumbers(bool getcollection)
private ienumerableiteratormethod()
}">public ienumerable getsingledigitoddnumbers(bool getcollection)
private ienumerable iteratormethod()
}
看看上面的方法。 第 1 個方法使用標準return
語句返回空集合,或返回第 2 個方法建立的迭代器。 第 2 個方法使用yield return
語句建立請求的序列。
foreach
語句可擴充套件為使用ienumerable
和ienumerator
介面的標準用語,以便迴圈訪問集合中的所有元素。 還可最大限度減少開發人員因未正確管理資源所造成的錯誤。
編譯器將第 1 個示例中顯示的foreach
迴圈轉換為類似於此構造的內容:
enumerator = collection.getenumerator();
while (enumerator.movenext())
">ienumerator enumerator = collection.getenumerator();
while (enumerator.movenext())
上述構造表示由 c# 編譯器版本 5 及更高版本生成的**。 在版本 5 之前,item
變數的範圍有所不同:
enumerator = collection.getenumerator();
int item = default(int);
while (enumerator.movenext())
">// c# versions 1 through 4:
ienumerator enumerator = collection.getenumerator();
int item = default(int);
while (enumerator.movenext())
此範圍更改的原因在於:較早行為可能導致難以診斷出有關 lambda 表示式的 bug。 若要詳細了解 lambda 表示式,請參閱 lambda 表示式。
編譯器生成的確切**更複雜一些,用於處理getenumerator()
返回的物件實現idisposable
的情況。 完整擴充套件生成的**更類似如下:
} finally
}
列舉器的釋放方式取決於enumerator
型別的特徵。 一般情況下,finally
子句擴充套件為:
finally
但是,如果enumerator
的型別為已密封型別,並且不存在從型別enumerator
到idisposable
的隱式轉換,則finally
子句擴充套件為乙個空白塊:
finally
如果存在從型別enumerator
到idisposable
的隱式轉換,並且enumerator
是不可為 null 的值型別,則finally
子句擴充套件為:
finally
幸運地是,無需記住所有這些細節。foreach
語句會為你處理所有這些細微差別。 編譯器會為所有這些構造生成正確的**。 大麥植髮婉之C vector容器
植髮費用?大麥植髮婉之c vector容器 我們在宣告陣列的時候,採用的是datatype arrayname len 的形式,陣列在分配之後,不能調整大小,刪除和插入資料時操作十分的繁瑣,雖然可以採用鍊錶,但是鍊錶的操作更麻煩,我們希望有更簡單的方法。與string類一樣,向量vector 同屬於...
大麥植髮婉之C語言巨集定義
植髮多少?大麥植髮婉之c語言巨集定義 巨集 macro 是預處理命令的一種,它允許用乙個識別符號來表示乙個字串。先看乙個例子 include define n 100 int main 執行結果 120該示例中的語句int sum 20 n n被100代替了。define n 100就是巨集定義,n...
大麥植髮婉之C 類的繼承與派生
植髮多少?大麥植髮婉之c 類的繼承與派生 繼承是物件導向程式設計中最重要的乙個概念。繼承允許我們根據乙個類來定義另乙個類,達到了 功能重用效果。當建立乙個類時,如果待建立的類與另乙個類存在某些共同特徵,程式設計師不需要全部重新編寫成員變數和成員函式,只需指定繼承另乙個類即可,被繼承的類稱為基類或父類...