将TPL与现有的异步api一起使用

本文关键字:api 一起 异步 TPL | 更新日期: 2023-09-27 18:04:47

我想使用现有API的TPL,具体来说是RestSharp,所以我可以使用延续。

但这意味着我必须包装一个API,它不采用经典的。net方法进行异步,而是实现回调。取一些像这样的代码:

var client = new RestClient("service-url");
var request = new RestRequest();
client.ExecuteAsync<List<LiveTileWeatherResponse>>(request, 
    (response) =>
    {
        ...
    });

如果可能的话,我想在TPL中包装ExecuteAsync。但我无论如何也想不出该怎么做。

任何想法?

将TPL与现有的异步api一起使用

TPL提供了TaskCompletionSource类,它允许您将几乎任何内容暴露为任务。通过调用SetResult或SetException,您可以导致任务成功或失败。在您的示例中,您可能会这样做:

static Task<T> ExecuteTask<T>(this RestClient client, RestRequest request)
{
    var tcs = new TaskCompletionSource<T>();
    client.ExecuteAsync<T>(request, response => tcs.SetResult(response));
    return tcs.Task;
}

你可以这样用:

var task = client.ExecuteTask<List<LiveTileWeatherResponse>>(request);
foreach (var tile in task.Result)
{}

或者,如果你想链接任务:

var task = client.ExecuteTask<List<LiveTileWeatherResponse>>(request);
task.ContinueWith(
    t => 
    {
        foreach (var tile in t.Result)
        {}
    }
);

你可以阅读更多关于TaskCompletionSource在http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx

这也是我学习TPL时的一个主要痛点。

你要找的是TaskCompletionSource。当你创建一个TaskCompletionSource时,它会创建一个特殊的Task对象(通过TaskCompletionSource.Task属性访问),只有当你在相关的TaskCompletionSource上调用SetResultSetException方法时才会完成。

这篇文章解释了如何将APM操作与TPL(以及Rx)打包。另请参见演示封装在TPL中的APM操作的要点。