0

请多多包涵 :-)

我在 C# 中的 TPL 上苦苦挣扎,我一直在努力找出设计解决方案的最佳方法,以启动多个异步任务,等待它们完成,然后继续。我的初始 POC 如下。每个 IDataGatherer 实例都需要获取数据并将其按摩到 DataObject 实例中。

  1. 我不确定如何处理来自 DownloadStringTaskAsync 调用的延续,以便我可以获取结果并将其按摩到 DataObject 中。ContinueWith 想要提供一个带有 void 返回签名的方法,但我觉得 ExtractData 方法需要返回一个 Task 实例,否则我没有 Task 实例可以从 GetDataAsync() 方法返回。

  2. 我还想知道是否需要在我的 IDataGatherer 实例中引入一个 TaskCompletionSource ,但我如何将它附加到正在执行实际工作的任务上 - 例如 DownloadstringTaskAsync 和 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

4

1 回答 1

2

首先,你不需要TaskCompletionSource. 那是因为ContinueWith() 可以提供一个非void签名的方法。例如:

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);
}
于 2013-02-26T20:58:53.763 回答