将基于回调的异步方法转换为可等待任务的最佳方法

转换/包装一个“经典”异步方法的最佳方法是什么? 这个方法使用一个回调函数来返回一个(可等待的)任务?

例如,给定以下方法:

public void GetStringFromUrl(string url, Action<string> onCompleted);

据我所知,将这个函数包装到返回任务的方法中的唯一方法是:

public Task<string> GetStringFromUrl(string url)
{
var t = new TaskCompletionSource<string>();


GetStringFromUrl(url, s => t.TrySetResult(s));


return t.Task;
}

这是唯一的办法吗?

有没有办法在任务本身中包装对 GetStringFromUrl (url,callback)的调用(也就是说,调用本身将在任务内部运行,而不是同步运行)

26323 次浏览

Your code is short, readable and efficient, so I don't understand why are you looking for alternatives, but I can't think of anything. I think your approach is reasonable.

I'm also not sure why do you think that the synchronous part is okay in the original version, but you want to avoid it in the Task-based one. If you think the synchronous part might take too long, fix it for both versions of the method.

But if you want to run it asynchronously (i.e. on the ThreadPool) only in the Task version, you can use Task.Run():

public Task<string> GetStringFromUrl(string url)
{
return Task.Run(() =>
{
var t = new TaskCompletionSource<string>();


GetStringFromUrl(url, s => t.TrySetResult(s));


return t.Task;
});
}

Your assumed implementation is perfectly fine for this assuming the callback only ever handles successful situations. What currently happens if an exception happens within the async underpinnings of the GetStringFromUrl implementation? There's no real way for them to propagate that to the Action callback... do they just swallow it and return you null or something?

The only thing I would recommend is using following the new convention of naming such async methods with the XXXAsync suffix.