Lets say that i have a couple of tasks:
void Sample(IEnumerable someInts)
{
var taskList = someInts.Select(x => DownloadSomeString(x));
}
Modified version of @Servy 's code because it contains some compile errors and several pitfalls. My variant is:
public static class AsyncExtensions
{
public static Task GetFirstSuccessfulTask(this IReadOnlyCollection> tasks)
{
var tcs = new TaskCompletionSource();
int remainingTasks = tasks.Count;
foreach (var task in tasks)
{
task.ContinueWith(t =>
{
if (task.Status == TaskStatus.RanToCompletion)
tcs.TrySetResult(t.Result);
else if (Interlocked.Decrement(ref remainingTasks) == 0)
tcs.SetException(new AggregateException(
tasks.SelectMany(t2 => t2.Exception?.InnerExceptions ?? Enumerable.Empty())));
});
}
return tcs.Task;
}
}
We don't have to ToList
our input because it's already a collection we can work with, it compiles (huge advantage) and it handles situation when exception for some reason doesn't have an innter exception (it's completely possible).