Reputation: 759
Should I do this?
int x = 0;
Task<int> calc = Task.Factory.StartNew (() => 7 / x);
try
{
Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
Console.Write (aex.InnerException.Message); // Attempted to divide by 0
}
or this?
int x = 0;
try
{
Task<int> calc = Task.Factory.StartNew (() => 7 / x);
Console.WriteLine (calc.Result);
}
catch (AggregateException aex)
{
Console.Write (aex.InnerException.Message); // Attempted to divide by 0
}
If the task starts immediately and before we are in the try catch block then, we wont catch it...!?
Upvotes: 1
Views: 135
Reputation: 25201
Tasks have an Exception
property that holds the exception that was thrown during the task's execution, if there was one. This means you can do this:
int x = 0;
Task<int> calc = Task.Factory.StartNew(() => 7 / x);
calc.ContinueWith(t => Console.WriteLine ("Got exception of {0}", t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
Upvotes: 0
Reputation: 18276
In this case you don't need to include it in the try block. Task.Factory.StartNew will not throw an exception unless you pass it a null Action to execute. Any exceptions thrown by the action being run will be propagated into the task, not up the stack.
More generally, I think the rule of thumb for these types of situations is that the exception should always go into the task. For example, if you throw an exception before the first await in an async method, it also goes into the resulting task instead of propagating up the stack.
Upvotes: 0
Reputation: 171178
You want to execute as little code as possible in your try block because the more you include the more spurious, unwanted exception you will catch. You only want to catch those of which you know they are benign. You don't want to swallow bugs.
Therefore either do this:
var task = ...;
int result;
try { result = task.Result; } //just catch task.Result
...
or even this:
if (task.Exception != null) { /* error */ }
else { /* use task.Result */ }
Upvotes: 0
Reputation: 244777
One of the points of using Task
is that you mostly don't have to worry about things like that.
As you noticed, there are two possible orders of events with your first sample:
StartNew()
is called from thread A.Result
getter is called from thread A. The task didn't finish yet, so the call blocks.DivideByZeroException
.Result
throws AggregateException
.The second possibility is:
StartNew()
is called from thread A.DivideByZeroException
.Result
getter is called from thread A. The task already finished, so the call immediately throws AggregateException
.As you see, in both cases the Result
getter throws the exception, it doesn't matter in what order did the code execute.
Your second version would only make sense if StartNew()
could throw AggregateException
, but that never happens.
Let me repeat: TPL takes care of all the synchronization, you don't have to worry about it here.
Upvotes: 1