public static class TaskCompletionExtensions { public static Task FirstCompletedTask(this IEnumerable> source) { foreach (var completedTask in tasks.InCompletionOrder()) { if (completedTask.Status == TaskStatus.RanToCompletion) { return completedTask; } } throw new Exception("None of the given tasks completed successfully."); // alternatively: return Task.FromResult(default(T)); } // Sourced from Jon Skeet public static IEnumerable> InCompletionOrder(this IEnumerable> source) { var inputs = source.ToList(); var boxes = inputs.Select(x => new TaskCompletionSource()).ToList(); int currentIndex = -1; foreach (var task in inputs) { task.ContinueWith(completed => { var nextBox = boxes[Interlocked.Increment(ref currentIndex)]; PropagateResult(completed, nextBox); }, TaskContinuationOptions.ExecuteSynchronously); } return boxes.Select(box => box.Task); } // Sourced from Jon Skeet private static void PropagateResult(Task completedTask, TaskCompletionSource completionSource) { switch(completedTask.Status) { case TaskStatus.Canceled: completionSource.TrySetCanceled(); break; case TaskStatus.Faulted: completionSource.TrySetException(completedTask.Exception.InnerExceptions); break; case TaskStatus.RanToCompletion: completionSource.TrySetResult(completedTask.Result); break; default: throw new ArgumentException ("Task was not completed."); } } }