假设我的代码如下所示:
public async Task<string> DoSomethingReturnString(int n) { ... }
int[] numbers = new int[] { 1, 2 , 3};
Run Code Online (Sandbox Code Playgroud)
假设我想创建一个字典,其中包含调用DoSomethingReturnString
与此类似的每个数字的结果:
Dictionary<int, string> dictionary = numbers.ToDictionary(n => n,
n => DoSomethingReturnString(n));
Run Code Online (Sandbox Code Playgroud)
这是行不通的,因为DoSomethingReturnString返回Task<string>
而不是string
.intellisense建议我尝试将我的lambda表达式指定为异步,但这似乎也没有解决问题.
如果你坚持用linq做,那么Task.WhenAll
"保湿"词典是关键:
int[] numbers = new int[] { 1, 2 , 3};
KeyValuePair<int, string>[] keyValArray = //using KeyValuePair<,> to avoid GC pressure
await Task.WhenAll(numbers.Select(async p =>
new KeyValuePair<int, string>(p, await DoSomethingReturnString(p))));
Dictionary<int, string> dict = keyValArray.ToDictionary(p => p.Key, p => p.Value);
Run Code Online (Sandbox Code Playgroud)
小智 8
这只是 @Yacoub 和 @David 对使用 Task.WhenAll 的扩展方法的答案的组合
public static async Task<Dictionary<TKey, TValue>> ToDictionaryAsync<TInput, TKey, TValue>(
this IEnumerable<TInput> enumerable,
Func<TInput, TKey> syncKeySelector,
Func<TInput, Task<TValue>> asyncValueSelector) where TKey : notnull
{
KeyValuePair<TKey, TValue>[] keyValuePairs = await Task.WhenAll(
enumerable.Select(async input => new KeyValuePair<TKey, TValue>(syncKeySelector(input), await asyncValueSelector(input)))
);
return keyValuePairs.ToDictionary(pair => pair.Key, pair => pair.Value);
}
Run Code Online (Sandbox Code Playgroud)
LINQ方法不支持异步操作(例如,异步值选择器),但是您可以自己创建一个。这是ToDictionaryAsync
支持异步值选择器的可重用扩展方法:
public static class ExtensionMethods
{
public static async Task<Dictionary<TKey, TValue>> ToDictionaryAsync<TInput, TKey, TValue>(
this IEnumerable<TInput> enumerable,
Func<TInput, TKey> syncKeySelector,
Func<TInput, Task<TValue>> asyncValueSelector)
{
Dictionary<TKey,TValue> dictionary = new Dictionary<TKey, TValue>();
foreach (var item in enumerable)
{
var key = syncKeySelector(item);
var value = await asyncValueSelector(item);
dictionary.Add(key,value);
}
return dictionary;
}
}
Run Code Online (Sandbox Code Playgroud)
您可以像这样使用它:
private static async Task<Dictionary<int,string>> DoIt()
{
int[] numbers = new int[] { 1, 2, 3 };
return await numbers.ToDictionaryAsync(
x => x,
x => DoSomethingReturnString(x));
}
Run Code Online (Sandbox Code Playgroud)
如果从异步方法调用,您可以编写一个包装方法,该方法创建一个新字典并通过迭代每个数字来构建字典,DoSomethingReturnString
依次调用您的:
public async Task CallerAsync()
{
int[] numbers = new int[] { 1, 2, 3 };
Dictionary<int, string> dictionary = await ConvertToDictionaryAsync(numbers);
}
public async Task<Dictionary<int, string>> ConvertToDictionaryAsync(int[] numbers)
{
var dict = new Dictionary<int, string>();
for (int i = 0; i < numbers.Length; i++)
{
var n = numbers[i];
dict[n] = await DoSomethingReturnString(n);
}
return dict;
}
Run Code Online (Sandbox Code Playgroud)