Некоторые API, такие как WebClient, используют Асинхронный шаблон на основе событий . Хотя это выглядит просто и, вероятно, хорошо работает в слабо связанных приложениях (скажем, BackgroundWorker в пользовательском интерфейсе), оно не очень хорошо сцепляется.
Например, вот многопоточная программа, поэтому асинхронная работа не блокируется. (Представьте, что это происходит в серверном приложении и вызывается сотни раз - вы не хотите блокировать ваши потоки ThreadPool.) Мы получаем 3 локальные переменные («состояние»), а затем делаем 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 упрощают эту задачу, но этот способ обработки событий, кажется, не предлагает никакого способа.