Using TPL/Tasks I can perform exception handling using inner try/catch statement:
Task.Factory.StartNew(
()=>
{
try
{
// Do stuff
}
catch
{
// Handle exception
}
});
Or using ContinueWith, like so:
Task.Factory.StartNew(
()=>
{
// Do stuff
}).ContinueWith(
task =>
{
if(task.Exception != null)
// Handle exception
});
Which method is more recommended to use? What are the cons and pros for each?
Exceptions are propagated when you use one of the static or instance Task. Wait methods, and you handle them by enclosing the call in a try / catch statement. If a task is the parent of attached child tasks, or if you are waiting on multiple tasks, multiple exceptions could be thrown.
For and Parallel. ForEach overloads do not have any special mechanism to handle exceptions that might be thrown. In this respect, they resemble regular for and foreach loops ( For and For Each in Visual Basic); an unhandled exception causes the loop to terminate as soon as all currently running iterations finish.
Exception Handling in C# is a process to handle runtime errors. We perform exception handling so that normal flow of the application can be maintained even after runtime errors. In C#, exception is an event or object which is thrown at runtime.
AggregateException is used to consolidate multiple failures into a single, throwable exception object. It is used extensively in the Task Parallel Library (TPL) and Parallel LINQ (PLINQ). For more information, see Exception Handling and How to: Handle Exceptions in a PLINQ Query.
If you are able to properly handle the exception within the method the task itself is throwing you should be catching it within that first task, and not in a continuation, unless you have some compelling reason not to do so. Creating a continuation at the same scope as the task itself (as is done in your second example) is needlessly adding more work.
It's either useful or necessary to handle exceptions in continuations when the exception is handled from an entirely different scope than where the task is defined. For example, if you have a method that is given some arbitrary task, and it has no idea what the definition of that task might be, but it needs to do something in the event that the code threw an exception you'll need to have a continuation that handles the exception.
Note that if you are going to have a continuation that handles an exception you can use TaskContinuationOptions.OnlyOnFaulted
to only run the continuation when the task throws an exception, rather than doing the check within the definition of the continuation.
It's largely down to what your design needs. Some things to consider:
Catch exceptions in the tasks that throw them
Handle exceptions in continuations
TaskScheduler
, e.g. running "primary" tasks on the thread pool but marshalling all exception logging onto a UI thread.Task
s whose code you don't supply are observed and handled appropriately, e.g. properly cleaning up after tasks created by TaskFactory.FromAsync
. Though depending on circumstances, that could as well be done by waiting on the Task
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With