整合回调

时间:2014-06-13 15:00:03

标签: c# multithreading asynchronous

这不是一个特定于语言的问题,但就我的具体情况而言,我使用的是C#。 (编辑:在进一步阅读之前,此问题的选定答案是特定于C#的语言)

我需要完成两个异步服务调用,然后从这两个回调中收集信息。由于代码生成器的性质,我基本上最终得到了我称之为" -Completed"使用服务调用的结果调用的事件处理程序。

因此,在这种情况下,我有两个单独的异步调用从两个不同的源收集数据。当他们完成后,我想合并数据,然后继续正常的工作流程。

所以,在C#样式的伪代码中:

MyAsyncServiceClient1 masc1 = new MyAsyncServiceClient1();
MyAsyncServiceClient2 masc2 = new MyAsyncServiceClient2();

masc1.MyCallCompleted += new EventHandler<MyCallCompletedEventArts>((sender, e) =>
{
    .. collect some data ..
});

masc2.MyCallCompleted += new EventHandler<MyCallCompletedEventArts>((sender, e) =>
{
    .. collect some more data ...
});

masc1.MyCall();
masc2.MyCall();

所以我的问题是,是否存在合并这样的异步回调的一般模式,以便我可以从两个回调中收集数据,然后使用组合数据执行某些操作?我的意思是,我知道有办法做到这一点。我过去曾设计过各种方法,但随着越来越多的异步编程,我发现这已经成为一种常见的模式,我想看看我是否能找到比定制解决方案更优雅,更通用的解决方案继续想出来。

1 个答案:

答案 0 :(得分:3)

我们可以做的是编写一种方法将您的活动转变为Task。 (这是您的某个类型的方法;您需要为每个事件创建这样的方法,除非两个类型都实现定义此事件的接口。)具有任务允许组合,聚合操作等使这样的问题更容易解决。

public static Task<MyCallCompletedEventArts> CallAsync(
    this MyAsyncServiceClient1 client)
{
    var tcs = new TaskCompletionSource<MyCallCompletedEventArts>();
    EventHandler<MyCallCompletedEventArts> handler = null;
    handler = (_, args) =>
    {
        tcs.TrySetResult(args);
        client.MyCallCompleted -= handler;
    };
    client.MyCallCompleted += handler;
    client.MyCall();
    return tcs.Task;
}

(注意我们跳过一些箍以确保我们的处理程序在第一次触发后被删除。如果在您的情况下恰好没有必要,可以简化代码。)

现在你可以写:

MyAsyncServiceClient1 masc1 = new MyAsyncServiceClient1();
MyAsyncServiceClient2 masc2 = new MyAsyncServiceClient2();

var results = await Task.WhenAll(masc1.CallAsync(), masc2.CallAsync());
DoSomethingWithFirstClientsArgs(results[0]);