简体   繁体   English

Task.WaitAll,如何找到导致 AggregateException 的任务

[英]Task.WaitAll, how to find the tasks causing AggregateException

Let's say that I got the following code:假设我得到了以下代码:

var tasks = BuildTaskList();
try
{
    Task.WaitAll(tasks.ToArray());
}
catch (AggregateException exception)
{

}

How do I know which task threw which of the exceptions in exception.InnerExceptions ?我怎么知道哪个任务在 exception.InnerExceptions 中抛出了哪些exception.InnerExceptions

You still have the list of Tasks , and each Task has an Exception property.您仍然拥有Tasks列表,并且每个Task都有一个Exception属性。 Using that you can figure out which exceptions belong with which Task .使用它,您可以确定哪些异常属于哪个Task

But, if you can, it'd be better to use Task.WhenAll or TaskFactory.ContinueWhenAll than do a blocking Wait.但是,如果可以,最好使用Task.WhenAllTaskFactory.ContinueWhenAll不是阻塞等待。

var throwers = tasks.Where(task => task.Exception != null);
        var t1 = Task.Factory.StartNew(() => Console.WriteLine("Task 1"));
        var t2 = Task.Factory.StartNew(() => Console.WriteLine("Task 2"));
        var t3 = Task.Factory.StartNew(() => { throw new InvalidOperationException(); });
        var t4 = Task.Factory.StartNew(() => Console.WriteLine("Task 4"));

        Task.Factory.ContinueWhenAll(new[] { t1, t2, t3, t4 }, tasks =>
            {
                foreach (var t in tasks)
                {
                    if (t.Status == TaskStatus.Faulted)
                    {
                        // this will run for t3
                        Console.WriteLine("This task has been faulted.");
                    }
                }
            });

Option1 (credit to @theodor-zoulias comment):选项1(归功于@theodor-zoulias 评论):

You can set the Exception.Data property with the task name:您可以使用任务名称设置Exception.Data属性:

var task1 = Task.Factory.StartNew(() =>
{
    try
    {
        throw new Exception();
    }
    catch (Exception exception)
    {
        exception.Data["task"] = "task1";
        throw exception;
    }
});

var task2 = Task.Factory.StartNew(() =>
{
    try
    {
        throw new Exception();
    }
    catch (Exception exception)
    {
        exception.Data["task"] = "task2";
        throw exception;
    }
});

try
{
    Task.WaitAll(task1, task2);
}
catch (AggregateException ae)
{
    foreach (var exception in ae.InnerExceptions)
    {
        Console.WriteLine($"Exception was thrown by {exception.Data["task"]}");
    }
}

Option2:选项2:

If you don't mind loosing the name of the exception's assembly information, You can set the Exception.Source ( doc ) property of the thrown exception based on the task name and look at it while iterating:如果您不介意丢失异常程序集信息的名称,您可以根据任务名称设置抛出异常的Exception.Source ( doc ) 属性并在迭代时查看它:

var t1 = Task.Factory.StartNew(() => 
{
    throw new Exception() { Source = "t1" };
});
var t2 = Task.Factory.StartNew(() => 
{
    throw new Exception() { Source = "t2" };
});

try
{
    Task.WaitAll(t1, t2);
}
catch (AggregateException ae)
{
    foreach (var exception in ae.InnerExceptions)
    {
        Console.WriteLine($"Exception was thrown by {exception.Source}");
    }
}

Will output:将输出:

Exception was thrown by t1异常被 t1 抛出

Exception was thrown by t2异常被 t2 抛出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM