请耐心等待: - )
我正在努力解决c#中的TPL问题,并试图找出设计解决方案的最佳方法,以启动多个异步任务,等待它们完成并继续前进。我最初的POC在下面。每个IDataGatherer实例都需要获取数据并将其按摩到DataObject实例中。
我不确定如何处理DownloadStringTaskAsync调用的延续,这样我就可以获取结果并将其按下到DataObject中。 ContinueWith希望提供一个带有void返回签名的方法,但我觉得ExtractData方法需要返回一个Task实例,否则我没有从GetDataAsync()方法返回的Task实例。
我也想知道我是否需要在我的IDataGatherer实例中引入一个TaskCompletionSource,但是如何将其与正在进行实际工作的任务相提并论呢?例如,以下来关于StringtringTaskAsync和ExtractData?
interface IDataGatherer
{
Task<DataObject> GetDataAsync();
}
class DataObject
{
public string Data { get; set; }
}
class IpGatherer : IDataGatherer
{
private readonly string _url = "http://ip.jsontest.com";
public Task<DataObject> GetDataAsync()
{
var tcs = new TaskCompletionSource<DataObject>(); // Do I need this???
var client = new WebClient();
// stuck here
var task = client.DownloadStringTaskAsync(_url).ContinueWith(ExtractData);
}
private void ExtractData(Task<string> obj)
{
}
}
class Program
{
private static void Main(string[] args)
{
// takes a list of IDataGatherers and waits for them
// all to complete, handles exceptions, etc.
}
}
以这种方式设计解决方案可能会使事情变得过于复杂,所以我愿意提出清理建议或更简洁地做这些建议。
我正在使用.NET 4.5
答案 0 :(得分:2)
首先,您不需要TaskCompletionSource
。这是因为ContinueWith()
可以提供非void
签名的方法。 E.g:
public Task<DataObject> GetDataAsync()
{
var client = new WebClient();
return client.DownloadStringTaskAsync(_url)
.ContinueWith((Func<Task<string>, DataObject>)ExtractData);
}
private DataObject ExtractData(Task<string> task)
{
return new DataObject(task.Result);
}
(使用Result
不会阻止,因为您可以确定Task
将在此时完成。)
但是,由于您使用的是DownloadStringTaskAsync()
,因此您可能使用.Net 4.5,这意味着您可以使用await
。这使代码更简单:
public async Task<DataObject> GetDataAsync()
{
var client = new WebClient();
var s = await client.DownloadStringTaskAsync(_url);
return ExtractData(s);
}
private DataObject ExtractData(string s)
{
return new DataObject(s);
}