Skip to content

Instantly share code, notes, and snippets.

@Joe4evr
Last active June 11, 2019 09:58
Show Gist options
  • Save Joe4evr/aa4631fec890b9c2a4d1e95c93376bd7 to your computer and use it in GitHub Desktop.
Save Joe4evr/aa4631fec890b9c2a4d1e95c93376bd7 to your computer and use it in GitHub Desktop.
public static class TaskCompletionExtensions
{
public static Task<T> FirstCompletedTask<T>(this IEnumerable<Task<T>> 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<Task<T>> InCompletionOrder<T>(this IEnumerable<Task<T>> source)
{
var inputs = source.ToList();
var boxes = inputs.Select(x => new TaskCompletionSource<T>()).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<T>(Task<T> completedTask,
TaskCompletionSource<T> 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.");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment