Is there default way to get first task that finished successfully?

前端 未结 4 1447
被撕碎了的回忆
被撕碎了的回忆 2020-12-10 05:37

Lets say that i have a couple of tasks:

void Sample(IEnumerable someInts)
{
    var taskList = someInts.Select(x => DownloadSomeString(x));
}

         


        
4条回答
  •  失恋的感觉
    2020-12-10 06:33

    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).

提交回复
热议问题