覆盖函数并包括async / await

时间:2013-06-01 11:07:55

标签: .net async-await

我有一个名为WebUtil的类,其中有一个名为GetWebpage()的抽象函数。在这个函数的一个实现中,我使用WebClient类,在另一个实现中我使用新的HttpClient及其await / async功能。问题是使用HttpClient要求方法返回Task<>,所以我改变了抽象方法定义。但是现在使用WebClient的函数也必须返回Task<>

有没有一个好方法来处理这个问题?有什么我不熟悉的吗?

3 个答案:

答案 0 :(得分:3)

您可以使用Task<> WebClient返回Task.FromResult

Task<string> GetWebPage(string url)
{
    var c = new WebClient();
    var html = c.DownloadString(url);
    return Task.FromResult(html);
}

或者,您可以使用TaskCompleteSource<T>将事件转换为任务:

Task<string> GetWebPage(string url)
{
    var c = new WebClient();
    var tcs = new TaskCompleteSource<string>();
    c.DownloadStringCompleted += (o, e) => tcs.SetResult((string)e.Result);
    c.DownloadStringAsync(new Uri(url));
    return tcs.Task;
}

答案 1 :(得分:1)

你必须坚持使用其中一个。就个人而言,我会选择异步并重写使用WebClient返回任务的覆盖。在功能方面,您将获得更多收益(例如,请参阅CancellationToken支持的代码段)。由于此方法的非阻塞性质,这也恰好是更好的设计。

    public override Task<string> GetWebpage(CancellationToken cancellationToken)
    {
        var client = new WebClient();
        var tcs = new TaskCompletionSource<string>();

        client.DownloadStringCompleted += (sender, e) =>
        {
            if (e.Cancelled)
            {
                tcs.SetCanceled();
            }
            else if (e.Error != null)
            {
                tcs.SetException(e.Error);
            }
            else 
            {
                tcs.SetResult(e.Result);
            }
        };

        client.DownloadStringAsync(this.Url);

        if (cancellationToken.CanBeCanceled)
        {
            cancellationToken.Register(client.CancelAsync);
        }

        return tcs.Task;
    }

答案 2 :(得分:0)

正如Stephen Cleary在评论中提到的,WebClient也支持async,因此您只需调用其中一种-TaskAsync方法。

但总的来说,使用async(如果方法很快)或Task.FromResult()(如果它很慢)实现Task.Run()接口是可以的。