title: How to overload and return multiple types with a C# async method?
body: <p>I want a bunch of <code>GetDataAsync()</code> methods which are overloaded to return various data sets based on the type needed. If the function weren't async, I could overload based on <code>out</code> parameters:</p>
  
  <pre><code>public void GetData(int userId, out int age, out string name) { ... }
  public void GetData(int userId, out string name, out string address) { ... }
  </code></pre>
  
  <p>But <code>out</code> isn't allowed for <code>async</code> methods. Next, I tried using generics to overload (I changed <code>string</code> and <code>int</code> for other types, since this trick wouldn't be valid for sealed classes):</p>
  
  <pre><code>public async Task&lt;Tuple&lt;TName, TAddress&gt;&gt; GetDataAsync&lt;TName, TAddress&gt;(int userId)
      where TAddress : Address where TName : Name
  { ... }
  public async Task&lt;Tuple&lt;TAge, TName&gt;&gt; GetDataAsync&lt;TAge, TName&gt;(int userId)
      where TAge : Age where TName : Name
  { ... }
  </code></pre>
  
  <p>But I gather template specialization doesn't really exist in C#, so these are considered to be the same function.</p>
  
  <p>The ugly hack that does enable this overload is passing in buffers which the function populates:</p>
  
  <pre><code>public async Task GetDataAsync(int userId, int[] id_output, string[] name_output)
  {
      await Task.Delay(10);
      id_output[0] = 60;
      name_output[0] = "Freddy";
  }
  
  public async Task GetDataAsync(int userId, string[] name_output, string[] address_output)
  {
      await Task.Delay(10);
      name_output[0] = "Freddy";
      address_output[0] = "Elm Street";
  }
  </code></pre>
  
  <p>But that hack has a bad API. (It would be a little safer using a list as a buffer.) Is there any proper C# way to get different data types from an async overload? If I must, I'll incorporate the datatypes into the function names instead of overloading, but that seems needlessly verbose. And since the functions abstract database calls, some of them would have very long names indeed! (These functions will mostly have more than one caller, hence the desire to define them centrally rather than in the class they're called from.)</p>