自从.NET4.5推出async/await语法,我们又多了一个炫耀的工具,可以用它来炫耀自己的编程水平,然后再嘲笑Java。然而,有些老旧的API只提供了基于事件的异步方法,而没有提供返回Task的异步方法,这会影响我们的炫耀效果。那么,我们该怎么办呢?
就像Windows Phone 8的webclient,只提供了基于事件的DownloadStringAsync
方法,写的时候就像这样:
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
...
};
client.DownloadStringAsync(...);
为了保住我们的逼格,大微软早就为我们提供了解决方法:TaskCompletionSource<T>
,非常适合把基于事件的异步封装成Task<T>
方法。这个类型返回是一个可以被await
的Task,事件callback的时候用SetResult()
就能给返回的Task设定结果了。封装后完整的代码如下,这是标准的做法:
private static Task<string> GetHtmlStringAsync(string url)
{
var tcs = new TaskCompletionSource<string>();
var client = new WebClient()
{
Encoding = DBCSEncoding.GetDBCSEncoding("gb2312")
};
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
tcs.SetResult(e.Result);
}
else
{
tcs.SetException(e.Error);
}
};
client.DownloadStringAsync(new Uri(url));
return tcs.Task;
}
现在我们就可以await
这个Task了:
var data = await GetHtmlStringAsync(url);
另外,如果你的API已经支持了基于事件的异步,名字叫做FixComputerAsync()
,你也想暴露一个基于Task的异步方法,那么怎么命名呢?我们已经有个Async结尾的方法了,为了有明显的区别,不建议使用重载。大微软自己的.NET Framework通常使用TaskAsync作为后缀,所以方法名字应该是FixComputerTaskAsync()
。