title: Convert a dictionary of tasks into a dictionary of results
body: <p>I have a program that has to process a number of objects and produce an analysis.  Each analysis results in a string, and the strings are concatenated to create a report. The report needs the results in a certain order, but I want to analyze each item asynchronously, so I manage this by putting everything into a dictionary, which I can then sort before preparing the final output.</p>
  
  <p>Note: For the sake of this example I will pretend that we are analyzing types from the current assembly, although in my case it's more complicated than that.</p>
  
  <p>The basic pattern (I thought) for doing this would be like this:</p>
  
  <pre><code>var types = myAssembly.GetTypes();
  var tasks = types.ToDictionary( key =&gt; key, value =&gt; AnalyzeType(value) );
  //AnalyzeType() is an async method that returns Task&lt;string&gt;.
  </code></pre>
  
  <p>Now we have a dictionary of hot tasks, which may or may not be finished by the time the dictionary is created, because I didn't await anything. </p>
  
  <p>Now to get the results. How do I do it?</p>
  
  <p><strong>Await</strong></p>
  
  <p>In theory all I have to do is await each task; the result of the await operation is the value itself. But this doesn't convert anything.</p>
  
  <pre><code>var results = tasks.ToDictionary( k =&gt; k.key, async v =&gt; await v.Value );
  Console.WriteLine(results.GetType().FullName);
  </code></pre>
  
  <p>Output:</p>
  
  <blockquote>
    <p><code>System.Collections.Generic.Dictionary'2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Threading.Tasks.Task'1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</code></p>
  </blockquote>
  
  <p>I am baffled... I thought by putting <code>await</code> in front of the Task, c# would convert it to the result. But I still have a dictionary of tasks.</p>
  
  <p><strong>GetResult()</strong></p>
  
  <p>Another approach would be to use this:</p>
  
  <pre><code>var results = tasks.ToDictionary( key =&gt; key, value =&gt; value.GetAwaiter().GetResult() );
  Console.WriteLine(results.GetType().FullName);
  </code></pre>
  
  <p>Output:</p>
  
  <blockquote>
    <p><code>System.Collections.Generic.Dictionary'2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</code></p>
  </blockquote>
  
  <p>So this appears to get me what I wanted, but I had to remove the <code>await</code> keyword, and now I get a warning from the compiler that the method will execute synchronously.</p>
  
  <p>I could add</p>
  
  <pre><code>await Task.WhenAll(tasks.Select( kvp =&gt; kvp.Value));
  </code></pre>
  
  <p>...to yield control until all the tasks have finished running (since it might take a while), so then my overall solution would be:</p>
  
  <pre><code>await Task.WhenAll(tasks.Select( kvp =&gt; kvp.Value));
  var results = tasks.ToDictionary( key =&gt; key, value =&gt; value.GetAwaiter().GetResult() );
  Console.WriteLine(results.GetType().FullName);
  </code></pre>
  
  <p>Which I guess works. But seems like this isn't the right way; I am suspicious of calling <code>GetAwaiter().GetResult()</code>, and I'd rather not do the extra <code>WhenAll()</code> step if it isn't needed, and it shouldn't be, since I'm getting the awaiters and results for each and every task individually.</p>
  
  <p>What is the right way to do this? Why didn't the <code>await</code> keyword work in my first example? Do I need to <code>GetResult()</code>? And if I do, is it a good idea to include <code>await Task.WhenAll()</code>, or is it better to simply rely on the <code>GetAwaiter()</code> call (which occurs later anyway)?</p>
  
  <p><a href="https://dotnetfiddle.net/VL290F" rel="noreferrer">Click here for a Fiddle</a> if you'd like to work with it.</p>
  
  <h1>Edit (answer):</h1>
  
  <p>Thanks Shaun for the correct answer. Here is a generalizable extension method if anyone wants something they can just drop into their code base.</p>
  
  <pre><code>public static async Task&lt;Dictionary&lt;TKey, TResult&gt;&gt; ToResults&lt;TKey,TResult&gt;(this IEnumerable&lt;KeyValuePair&lt;TKey, Task&lt;TResult&gt;&gt;&gt; input)
  {
      var pairs = await Task.WhenAll
      (
          input.Select
          ( 
              async pair =&gt; new { Key = pair.Key, Value = await pair.Value }
          )
      );
      return pairs.ToDictionary(pair =&gt; pair.Key, pair =&gt; pair.Value);
  }
  </code></pre>