以下代码是否捕获了TPL中原始,继续和子任务的异常?

Dre*_*mer 5 .net c# asynchronous task-parallel-library async-await

我正在使用TPL和async/await在我的应用程序的webclient上构建异步API.很少有地方(通常我需要运行一堆异步任务并最终等待所有这些),我正在关注代码片段.我只是想确保我正确,因为尽管使用TPL编写异步代码相对容易并且async/await 调试/故障排除仍然具有挑战性(客户站点上的交互式调试和故障排除问题) - 所以想要正确.

我的目标:能够捕获从原始任务,继续任务以及子任务生成的异常,以便我可以处理它(如果需要).我不希望任何例外都被冷杉和遗忘.

我使用的基本原理: 1.net框架确保将异常附加到任务2.可以将try/catch块应用于async/await以提供同步代码的幻觉/可读性(参考:http://channel9.msdn. com/Events/TechDays/Techdays-2014-the-Netherlands/Async-programming-deep-dive,http://blogs.msdn.com/b/ericlippert/archive/2010/11/19/asynchrony-in-c- 5-part-seven-exceptions.aspx,http://msdn.microsoft.com/en-us/library/dd537614.aspx等)

问题 我想获得批准,已经实现了期望的目标(我可以从原始,继续和子任务中捕获异常),并且我可以对样本做任何改进:

例如,是否存在其中一个组合任务(例如,未解包的代理任务)根本不会被激活(waitforactivation状态)的情况,那么waitall可能只是等待任务开始?我的理解是这些情况永远不会发生,因为延续任务总是执行,并返回由代理使用wnwrap跟踪的任务.只要我在所有层和apis中遵循类似的模式,模式应该捕获链接任务中的所有聚合异常.

注意:基本上我正在寻找建议,例如,如果原始任务状态没有运行完成,或者使用附加到父级,那么我就可以避免在继续任务中创建虚拟任务,这样我就可以只在父级等上查看所有可能性以便我可以选择最好的选择,因为这个模式非常依赖我的应用程序进行错误处理.

static void SyncAPIMethod(string[] args)
        {
            try
            {
                List<Task> composedTasks = new List<Task>();
                //the underlying async method follow the same pattern
                //either they chain the async tasks or, uses async/await 
                //wherever possible as its easy to read and write the code
                var task = FooAsync();
                composedTasks.Add(task);
                var taskContinuation = task.ContinueWith(t =>
                    {
                        //Intentionally not using TaskContinuationOptions, so that the 
                        //continuation task always runs - so that i can capture exception
                        //in case something is wrong in the continuation
                        List<Task> childTasks = new List<Task>();
                        if (t.Status == TaskStatus.RanToCompletion)
                        {

                            for (int i = 1; i <= 5; i++)
                            {
                                var childTask = FooAsync();
                                childTasks.Add(childTask);
                            }

                        }
                        //in case of faulted, it just returns dummy task whose status is set to 
                        //'RanToCompletion'
                        Task wa = Task.WhenAll(childTasks);
                        return wa;
                    });
                composedTasks.Add(taskContinuation);
                //the unwrapped task should capture the 'aggregated' exception from childtasks
                var unwrappedProxyTask = taskContinuation.Unwrap();
                composedTasks.Add(unwrappedProxyTask);
                //waiting on all tasks, so the exception will be thrown if any of the tasks fail
                Task.WaitAll(composedTasks.ToArray());
            }
            catch (AggregateException ag)
            {
                foreach(Exception ex in ag.Flatten().InnerExceptions)
                {
                    Console.WriteLine(ex);
                    //handle it
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

最好的祝福.