AsyncEnumerator 的體系結構
AsyncEnumerator 類可定義圖 3 中顯示的私有字段。 m_enumerator 字段指您的迭代器成員,構造函數會將此字段初始化為空,然後 Execute 會將此字段設置 為傳遞給它的值。m_inbox 字段指 IAsyncResult 對象的集合。m_waitAndInboxCounts 字段是一個包含 有兩個 16 位整數值的結構;在本專欄的稍後部分,我將介紹如何使用這些值。
圖 3 AsyncEnumerator 字段
public partial class AsyncEnumerator {
// Refers to the iterator member's code
private IEnumerator<Int32> m_enumerator;
// Collection of completed async Operations (the inbox)
private List<IAsyncResult> m_inbox =
new List<IAsyncResult>();
// Structure with Wait & Inbox counters
private WaitAndInboxCounts m_waitAndInboxCounts;
}
正如我在上期專欄中所介紹的,要使編譯器創建用於實現 IEnumerator<T> 接口的類,使用迭 代器確實是一種簡便方式。通常,您會使用 foreach 語句遍歷 IEnumerator<T> 對象。不過,無 論何時您都可以顯式調用代碼中的 IEnumerator<T> MoveNext 方法和 Current 屬性,這正是 AsyncEnumerator 類的作用。
AsyncEnumerator 的 Execute 方法將在內部調用名為 ResumeIterator 的私有方法(如圖 4 中所示 )。此方法用於啟動迭代器,還可用於使迭代器從暫停狀態恢復執行。
圖 4 ResumeIterator
private void ResumeIterator() {
Boolean continueIterating;
// While there are more Operations to perform...
while (continueIterating = m_enumerator.MoveNext()) {
// Get the value returned from the enumerator
UInt16 numberOpsToWaitFor = checked((UInt16) m_enumerator.Current);
// If inbox has fewer items than requested, keep iterator suspended
if (!m_waitAndInboxCounts.AtomicSetWait(numberOpsToWaitFor)) break;
// Inbox has enough items, loop to resume the iterator
}
// The iterator is suspended, just return
if (continueIterating) return;
// The iterator has exited, execute the iterator's finally code
m_enumerator.Dispose();
}
當線程調用 ResumeIterator 時,它將調用 IEnumerator<T> MoveNext 方法,用於喚醒並運行 迭代器。如果迭代器退出或執行 yield break 語句,IEnumerator<T> MoveNext 方法將返回 false,表明它沒有可執行的操作。如果將 ResumeIterator 方法的 continueIterating 變量設置為 false,它將退出此循環,並調用 IEnumerator<T> 對象的 Dispose 方法,允許執行清理。然後, ResumeIterator 方法將返回值,因為迭代器已完成其所有工作。
另一方面,如果枚舉器對象的 MoveNext 方法返回 true,則表明它已啟動了一些異步操作,並已通過 執行 yield return 語句暫停運行。現在,ResumeIterator 方法需要知道 IEnumerator<T> 對象 在其 yield return 語句中指定的數字。此數字指示在恢復運行迭代器之前應完成的異步操作數。為了獲 得此數字,ResumeIterator 將查詢枚舉器對象的 Current 屬性;此屬性將返回上次通過 yIEld return 語句指定的值。
隨後,ResumeIterator 將調用 WaitAndInboxCounts AtomicSetWait 方法,該方法用於設置迭代器應 等待的項目數。如果 AtomicSetWait 發現收件箱中的項目數少於此等待計數,則 AtomicSetWait 將返回 false,這會導致 ResumeIterator 返回值,因為此線程沒有其他任務可執行。如果 AtomicSetWait 發現 收件箱中的項目數大於或等於等待計數,則 AtomicSetWait 將返回 true 並繼續循環,從而再次調用枚 舉器對象的 MoveNext 方法,並允許迭代器恢復執行,以便處理已完成的操作。