ApmPatternWithMultipleMethods 方法顯示了如何使用公共語言運行時 (CLR) 的 APM,來執行與 SynchronousPattern 方法相同的操作。您會立即看到實現過程要復雜得多。請注意, ApmPatternWithMultipleMethods 方法會啟動異步 I/O 操作,操作完成時會調用 ReadCompleted 方法。 同時請注意,兩個方法之間的數據傳遞是通過將共享數據封裝到 ApmData 類的實例來完成的,為此我必 須專門進行定義,以便啟用這兩個方法之間的數據傳遞。還應注意,不能使用 C# using 語句,因為 FileStream 是在一個方法中打開,然後在另一個方法中關閉的。為彌補這個問題,我編寫了代碼,用於 在 ReadCompleted 方法返回之前顯式調用 FileStream 的 Close 方法。
ApmPatternWithAnonymousMethod 方法展示了如何使用 C# 2.0 稱為匿名方法的新功能重新編寫此代 碼,通過此功能您可以將代碼作為參數傳遞到方法。它能有效地讓您將一個方法的代碼嵌入到另一個方法 的代碼中。(我在所著書籍“CLR via C#”(CLR 編程之 C# 篇)(Microsoft Press, 2006) 中詳細說明 了匿名方法。)請注意,ApmPatternWithAnonymousMethod 方法要簡短得多,也更易於理解 — 在習慣使 用匿名方法後就可以體會到這一點。
首先,請注意該代碼較簡單,因為它完全包含在一個方法內。在此代碼中,我將調用 BeginRead 方法 啟動異步 I/O 操作。所有 BeginXxx 方法會將其第二個至最後一個參數視為一個引用方法的委托,即 AsyncCallback,該方法在操作完成時由線程池線程進行調用。通常,使用 APM 時,您必須編寫單獨的方 法,為該方法命名,並通過 BeginXxx 方法的最後一個參數將額外數據傳遞到該方法。但是,匿名方法功 能允許只編寫單獨的內嵌方法,這樣啟動請求和處理結果的所有代碼便會和環境協調。實際上,該代碼看 上去與 SynchronousPattern 方法有些類似。
其次,請注意 ApmData 類不再是必需的;您不需要定義該類、構造其實例以及使用它的任何字段!這 是如何實現的?其實,匿名方法的作用不僅僅限於將一個方法的代碼嵌入另一個方法的代碼中。當 C# 編 譯器檢測到外部方法中聲明的任何參數或局部變量也用於內部方法時,該編譯器實際上會自動定義一個類 ,並且兩個方法之間共享的每個變量會成為此編譯器定義的類中的字段。然後,在 ApmPatternWithAnonymousMethod 方法內,編譯器會生成代碼以構造此類的實例,且引用變量的任何代碼 都會編譯成訪問編譯器所定義類的字段的代碼。編譯器還使得內部方法成為新類上的實例方法,允許其代 碼輕松地訪問字段,現在兩個方法可以共享數據。
這是匿名方法的出色功能,它可讓您像使用方法參數和局部變量一樣編寫代碼,但實際上編譯器會重 新編寫您的代碼,從堆棧中取出這些變量,並將它們作為字段嵌入對象。對象可在方法之間輕松傳遞,並 且可以從一個線程輕松遷移到另一個線程,這對於使用 APM 而言是十分完美的。由於編譯器會自動執行 所有的工作,您可以很輕松地將最後一個參數的空值傳遞到 BeginRead 方法,因為現在沒有要在方法和 線程之間顯式傳遞的數據。但是,我仍然無法使用 C# using 語句,因為此處有兩個不同的方法,盡管看 上去似乎只有一個方法。
以下內容顯示了執行圖 1 中摘錄的代碼後的輸出。
Primary ThreadId=1
ThreadId=1: 4D-5A-90-00-03 (SynchronousPattern)
ThreadId=3: 4D-5A-90-00-03 (ApmPatternWithMultipleMethods)
ThreadId=3: 4D-5A-90-00-03 (ApmPatternWithAnonymousMethod)
ThreadId=3: 4D-5A-90-00-03 (ApmPatternWithLambdaExpression)
ThreadId=3: 4D-5A-90-00-03 (ApmPatternWithIterator)
我讓 Main 方法顯示應用程序主線程的托管線程 ID。然後我讓 ProcessData 方法顯示執行該方法的 線程的托管線程 ID。如您所見,輸出顯示了所有異步模式讓主線程之外的其他線程執行結果,而同步模 式則讓應用程序的主線程執行所有工作。
還應指出,C# 3.0 引入了一個新功能,稱為 lambda 表達式。在執行同一操作時,lambda 表達式功 能的語法比 C# 匿名方法功能更簡潔。實際上,這對於 C# 團隊來說是一個麻煩,因為現在它必須記錄和 支持產生相同結果的兩個不同語法。為了使用 C# 3.0 lambda 表達式功能, ApmPatternWithAnonymousMethod 方法經修改後成為圖 1 中所示的 ApmPatternWithLambdaExpression 方法。在此處可以看到語法略為簡化,因為編譯器能夠自動推斷出結果參數的類型為 IAsyncResult,而 且“=>”要鍵入的內容比“delegate”少。