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);
InnerException
is a property ofException
with returns 'the exception that caused this exception'.InnerExceptions
is a property unique toAggregateException
. 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 fromInnerExceptions
.To answer your other question re the behaviour of your sample code, the difference is the
TaskCreationOptions
default forTask.Run
. The default isTaskCreationOptions.DenyChildAttach
. You can read more about that in this blog post.