title: Writing a Task.WhenAll/WhenAny variant that cancels all other tasks on first faulted/Cancelled task
body: <p>I'm fairly new to C# and started playing around with the TPL today. I decided to write a modified version of 
  <strong>Task Task.WhenAll</strong> as an exercise. I'd like for it to have the following behavior:</p>
  
  <ul>
  <li>Upon finding the first task that has faulted or been canceled, cancel the rest of the tasks instead of waiting for them to finish.</li>
  <li>If the task faulted, the returned task should have the right exception set (i.e no swallowing by continuation and replacing with OperationCancelledException())</li>
  <li>No async in the method signature (want to avoid bubbling it up).</li>
  </ul>
  
  <p>I came up with the following crazy/stupid piece of code that doesn't work and I am having a hard time visualizing what's going on. I can't imagine any blocking going on and what i envisioned happening was a chain of tasks each waiting on the rest for completion. Could someone explain what's going on?</p>
  
  <p>I wouldn't have it in production code and this is just to test my fundamentals. I realize an easier way of doing this would be to do a Task.WhenAll and have the tasks in the list themselves have continuations that do the cancellation on failure.</p>
  
  <pre><code>    public static Task WhenAllError(List&lt;Task&gt; tasks, CancellationToken ct)
      {
          var tcs = new TaskCompletionSource&lt;object&gt;();
          return Task.WhenAny(tasks).ContinueWith&lt;Task&gt;((t) =&gt;
               {
                   if (tasks.Count == 0)
                   {
                       tcs.SetResult(null);
                       return tcs.Task;
                   }
  
                   if (t.IsFaulted)
                   {
                       Console.WriteLine("Task faulted. Cancelling other tasks: {0}", t.Id);
                       cts.Cancel();
                       // Make sure the tasks are cancelled if necessary
                       tcs.SetException(t.Exception);
                       return tcs.Task;
                   }
                   // Similarly handle Cancelled
  
                   tasks.Remove(t);
                   return WhenAllError(tasks, ct);
               }).Unwrap();
      }
  </code></pre>