WebClient などの一部の API は、イベント ベースの非同期パターンを使用します。これは単純に見え、疎結合のアプリ (UI の BackgroundWorker など) ではうまく機能する可能性がありますが、連鎖はあまりうまくいきません。
たとえば、非同期処理がブロックされないようにマルチスレッド化されたプログラムを次に示します。(これがサーバー アプリで行われ、何百回も呼び出されると想像してください。ThreadPool スレッドをブロックしたくありません。) 3 つのローカル変数 (「状態」) を取得し、2 つの非同期呼び出しを行い、その結果を最初に2番目のリクエストにフィードします(したがって、それらは並行して進むことができません)。状態も変化する可能性があります (簡単に追加できます)。
WebClient を使用すると、次のようになります (または、クロージャーのように動作するオブジェクトの束を作成することになります)。
using System;
using System.Net;
class Program
{
static void onEx(Exception ex) {
Console.WriteLine(ex.ToString());
}
static void Main() {
var url1 = new Uri(Console.ReadLine());
var url2 = new Uri(Console.ReadLine());
var someData = Console.ReadLine();
var webThingy = new WebClient();
DownloadDataCompletedEventHandler first = null;
webThingy.DownloadDataCompleted += first = (o, res1) => {
if (res1.Error != null) {
onEx(res1.Error);
return;
}
webThingy.DownloadDataCompleted -= first;
webThingy.DownloadDataCompleted += (o2, res2) => {
if (res2.Error != null) {
onEx(res2.Error);
return;
}
try {
Console.WriteLine(someData + res2.Result);
} catch (Exception ex) { onEx(ex); }
};
try {
webThingy.DownloadDataAsync(new Uri(url2.ToString() + "?data=" + res1.Result));
} catch (Exception ex) { onEx(ex); }
};
try {
webThingy.DownloadDataAsync(url1);
} catch (Exception ex) { onEx(ex); }
Console.WriteLine("Keeping process alive");
Console.ReadLine();
}
}
このイベントベースの非同期パターンをリファクタリングする一般的な方法はありますか? (つまり、このような API ごとに詳細な拡張メソッドを記述する必要はありませんか?) BeginXXX と EndXXX を使用すると簡単ですが、このイベントの方法では方法がないようです。