I want to use ToDictionary
on a bunch of Task<MyObject>
(see below). This works ok if I use TheTask.Result
, but not await
This works:
Dictionary<CarId, Task<Model>> allModelTasks = carIds.ToDictionary(cId =>cId, cId=> GetModelForCar(cId));
await Task.WhenAll(allModelTasks.Values);
Dictionary<CarId, Model> allModels = allModelTasks.ToDictionary(mt => mt.Key, mt => mt.Value.Result);
But if I replace last row with
Dictionary<CarId, Model> allModels = allModelTasks.ToDictionary(mt => mt.Key, async mt => await mt.Value);
I get an error message that says "cant convert from Dict<CarId, Task<Model>>
to Dict<CarId, Model>
".
As I see it, the rows should be equivalent.
(The recommendation from here, seems to be to use await instead of .Result
, even after EDIT Task.WhenAll
)
You seem to be ignoring that to be able to write await
in that last line, you also had to add another async
. Which means the await
isn't "in" your current method - it's inside a new async
lambda that, of course, being async
returns a Task
.
You can't use await
inside a lambda here and expect not to still have a task to unwrap. Your first code is fine, and doesn't suffer any of the potential problems that accessing .Result
can cause because the Task
s are all known to already be complete.
You could create or copy some form of ToDictionaryAsync
extension method into your class, something like:
public static class TaskResultExtensions
{
public static async Task<Dictionary<TKey, TValue>> ToDictionaryAsync<TKey, TValue>(this IEnumerable<KeyValuePair<TKey, Task<TValue>>> source)
{
var dict = new Dictionary<TKey, TValue>();
foreach (var kvp in source)
{
dict.Add(kvp.Key, await kvp.Value);
}
return dict;
}
}
Which would then allow your final line to be
Dictionary<CarId, Model> allModels = await allModelTasks.ToDictionaryAsync();
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With