我有一个名为的类WebUtil
,其中有一个名为GetWebpage()
. 在这个函数的一个实现中,我使用WebClient
类,在另一个实现中,我使用HttpClient
带有等待/异步功能的新类。问题是使用HttpClient
需要返回的方法Task<>
,所以我更改了抽象方法定义。但是现在使用 的函数WebClient
也必须 return Task<>
。
有没有好的方法来处理这个?有什么我不熟悉的吗?
我有一个名为的类WebUtil
,其中有一个名为GetWebpage()
. 在这个函数的一个实现中,我使用WebClient
类,在另一个实现中,我使用HttpClient
带有等待/异步功能的新类。问题是使用HttpClient
需要返回的方法Task<>
,所以我更改了抽象方法定义。但是现在使用 的函数WebClient
也必须 return Task<>
。
有没有好的方法来处理这个?有什么我不熟悉的吗?
您可以Task<>
使用WebClient
with返回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;
}
您将不得不坚持其中一个。就个人而言,我会选择异步并重新设计使用 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;
}
正如 Stephen Cleary 在评论中提到的那样,WebClient
它也支持async
,所以你可以调用其中一种-TaskAsync
方法。
但总的来说,async
使用Task.FromResult()
(如果方法快)或Task.Run()
(如果方法慢)实现接口是可以的。