C# InnerException in AggregateException

10.6k views Asked by At

I have this code as below to capture the exceptions throw from tasks created by using TaskFactory and Task.Run. If I use the TaskFactory, I am able to check the Exception thrown from the previous task in the Continued task without having to use the Task.WaitAll method. If I use Task.Run, the Continued task will not execute unless I explicitly Wait for the child tasks to finish. Which flag in the TaskFactory.StartNew changed this behaviour?

Also what is the difference between InnerException and InnerExceptions in AggregateException class? The InnerExceptions returns me a readonly collection of all exceptions thrown by the child tasks. The InnerException returns an AggregateExcpetion of exception thrown by only one child task.

//Use Factory
TaskCreationOptions atp = TaskCreationOptions.AttachedToParent;
Task.Factory.StartNew(() =>
{
    Task.Factory.StartNew (() => { throw null; }, atp);
    Task.Factory.StartNew (() => { throw new NullReferenceException();}, atp);
    Task.Factory.StartNew (() => { throw new Exception("Test"); }, atp);
})
.ContinueWith (p => p.Exception.Dump(),TaskContinuationOptions.OnlyOnFaulted);

//Use Task.Run
Task.Run(()=>
{
    TaskCreationOptions op = TaskCreationOptions.AttachedToParent;
    var t1 = Task.Factory.StartNew(()=> {throw null;}, op);
    var t2 = Task.Factory.StartNew(()=> {throw new NullReferenceException();}, op);
    var t3 = Task.Factory.StartNew(()=> {throw new Exception("Test");}, op);

    //This will trigger the continued task
    //Task.WaitAll(new Task[]{t1,t2,t3}); 
}).ContinueWith(task => {task.Exception.Dump();}, TaskContinuationOptions.OnlyOnFaulted);
1

There are 1 answers

6
Charles Mager On BEST ANSWER
  • InnerException is a property of Exception with returns 'the exception that caused this exception'.
  • InnerExceptions is a property unique to AggregateException. Due to its design, an aggregate exception can contain multiple 'causing' exceptions.

As the property InnerException is inherited, it makes sense that it returns the first exception from InnerExceptions.

To answer your other question re the behaviour of your sample code, the difference is the TaskCreationOptions default for Task.Run. The default is TaskCreationOptions.DenyChildAttach. You can read more about that in this blog post.