自从有了.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()。
为什么还用WebClient?用HttpClient多好,自带各种async接口……