解决两个异步代码示例

时间:2014-08-18 22:13:27

标签: c# asynchronous

我需要从网址列表中返回Dictionary<string, byte[]>

我有一个异步执行的代码示例,但只返回一个List<byte[]>,另一个似乎正在强制转换对象但是引发了线程错误。

//Seems to assign to the output type correctly, but doesn't execute properly
async Task<Dictionary<string, byte[]>> ReturnFileData(IEnumerable<string> urls)
{
    Dictionary<Uri, Task<byte[]>> dictionary;

    using (var client = new WebClient())
    {
        dictionary = urls.Select(url => new Uri(url)).ToDictionary(
            uri => uri, client.DownloadDataTaskAsync);
        await Task.WhenAll(dictionary.Values);
    }

    return dictionary.ToDictionary(pair => Path.GetFileName(pair.Key.ToString()), pair => pair.Value.Result);
}

//Executes properly, but isn't returning the right output type
async Task<List<byte[]>> ReturnFileData2(IEnumerable<string> urls)
{
    Dictionary<Uri, Task<byte[]>> dictionary;
    var tasks = urls.Select(uri => new WebClient().DownloadDataTaskAsync(uri));
    var results = await Task.WhenAll(tasks);

    return results.Select(result => result).ToList();
}

如何处理ReturnFileData2()并修正它以在输出中将Uri的文件名与byte[]一起投射?

2 个答案:

答案 0 :(得分:3)

你应该坚持使用ReturnFileData,但重做它以为每个URL使用单独的客户端:

async Task<Dictionary<string, byte[]>> ReturnFileData(IEnumerable<string> urls)
{
    Dictionary<Uri, Task<byte[]>> dictionary = urls
        .Select(url => new Uri(url))
        .ToDictionary(uri => uri, GetTheDataAsync);

    await Task.WhenAll(dictionary.Values);

    return dictionary
        .ToDictionary(
            pair => Path.GetFileName(pair.Key.ToString()),
            pair => pair.Value.Result);
}

async Task<byte[]> GetTheDataAsync(Uri uri)
{
    using (var client = new WebClient())
    {
        return await client.DownloadDataTaskAsync(uri);
    }
}

答案 1 :(得分:1)

我建议您使用较新的HttpClient

async Task<Dictionary<string, byte[]>> ReturnFileDataAsync(IEnumerable<string> urls)
{
  Dictionary<string, Task<byte[]>> dictionary;

  using (var client = new HttpClient())
  {
    dictionary = urls.ToDictionary(uri => uri, client.GetByteArrayAsync);
    await Task.WhenAll(dictionary.Values);
  }

  return dictionary.ToDictionary(pair => Path.GetFileName(pair.Key), pair => pair.Value.Result);
}

虽然我可能会这样写,但是避免使用中间字典:

async Task<Dictionary<string, byte[]>> ReturnFileDataAsync(IEnumerable<string> urls)
{
  using (var client = new HttpClient())
  {
    var results = await Task.WhenAll(urls.Select(async url => new
    {
      Key = Path.GetFileName(url), 
      Value = await client.GetByteArrayAsync(url),
    }));
    return results.ToDictionary(x => x.Key, x => x.Value);
  }
}