如何使用异步调用的结果来水合词典?

假设我的代码如下所示:

public async Task DoSomethingReturnString(int n) { ... } int[] numbers = new int[] { 1, 2 , 3}; 

假设我想创建一个字典,其中包含为每个与此类似的数字调用DoSomethingReturnString的结果:

 Dictionary dictionary = numbers.ToDictionary(n => n, n => DoSomethingReturnString(n)); 

这不起作用,因为DoSomethingReturnString返回Task而不是string 。 intellisense建议我尝试将我的lambda表达式指定为异步,但这似乎也没有解决问题。

如果你坚持使用linq, Task.WhenAll是“保湿”字典的关键:

 int[] numbers = new int[] { 1, 2 , 3}; KeyValuePair[] keyValArray = //using KeyValuePair<,> to avoid GC pressure await Task.WhenAll(numbers.Select(async p => new KeyValuePair(p, await DoSomethingReturnString(p)))); Dictionary dict = keyValArray.ToDictionary(p => p.Key, p => p.Value); 

LINQ方法不支持异步操作(例如,异步值选择器),但您可以自己创建一个。 这是一个可重用的ToDictionaryAsync扩展方法,它支持异步值选择器:

 public static class ExtensionMethods { public static async Task> ToDictionaryAsync( this IEnumerable enumerable, Func syncKeySelector, Func> asyncValueSelector) { Dictionary dictionary = new Dictionary(); foreach (var item in enumerable) { var key = syncKeySelector(item); var value = await asyncValueSelector(item); dictionary.Add(key,value); } return dictionary; } } 

你可以像这样使用它:

 private static async Task> DoIt() { int[] numbers = new int[] { 1, 2, 3 }; return await numbers.ToDictionaryAsync( x => x, x => DoSomethingReturnString(x)); } 

如果从异步方法调用,您可以编写一个包装器方法,通过迭代每个数字来创建一个新的字典并构建一个字典,依次调用您的DoSomethingReturnString

 public async Task CallerAsync() { int[] numbers = new int[] { 1, 2, 3 }; Dictionary dictionary = await ConvertToDictionaryAsync(numbers); } public async Task> ConvertToDictionaryAsync(int[] numbers) { var dict = new Dictionary(); for (int i = 0; i < numbers.Length; i++) { var n = numbers[i]; dict[n] = await DoSomethingReturnString(n); } return dict; }