自从.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()