Starting with .NET 4.6 there is a Task.FromException
method in the BCL.
There's also Task.FromCanceled
.
Question
My understanding is that return Task.FromResult(foo)
is a simple shorthand for:
var tcs = new TaskCompletionSource<TFoo>();
tcs.SetResult(foo);
return tcs.Task;
Is there some equivalent for a task that returns an exception state?
var tcs = new TaskCompletionSource<TFoo>();
tcs.SetException(new NotSupportedException()); // or whatever is appropriate
return tcs.Task;
I don't see anything like Task.FromException
. Or would it be more appropriate to just throw the exception without returning a task?
Solution
Starting with .NET 4.6 there is a Task.FromException
method in the BCL.
There's also Task.FromCanceled
.
OTHER TIPS
My understanding is that return Task.FromResult(foo) is a simple shorthand for... [
TaskCompletionSource.SetResult
].
Actually, Task.FromResult
doesn't use TaskCompletionSource
, its implementation is much simpler than that.
Is there some equivalent for a task that returns an exception state?
I reckon TaskCompletionSource
would be the best option for this. You could also do something like this:
static Task FromExAsync(Exception ex)
{
var task = new Task(() => { throw ex; });
task.RunSynchronously();
return task;
}
The exception will not be propagated outside the returned task
, until observed via await task
or task.Wait()
, which should be a desired behavior.
Note that if the exception passed to FromExAsync
is an active exception (i.e. has been already thrown and caught elsewhere), re-throwing it like this would loose the current stack trace and Watson buckets information stored inside the exception. There are two ways of dealing with it:
AggregateException
. This will make the original exception available as AggregateException.InnerException
:static Task FromExAsync(Exception ex)
{
var task = new Task(() => { throw new AggregateException(ex); });
task.RunSynchronously();
return task;
}
ExceptionDispatchInfo.Capture
to flow the active exception's state:static Task FromExAsync(Exception ex)
{
var ei = System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex);
var task = new Task(() => { ei.Throw(); });
task.RunSynchronously();
return task;
}
Finally, perhaps the simplest yet the worst option (due to the overhead of the state machine and the compiler warning) is to throw from an async
method:
static async Task FromExAsync(Exception ex)
{
throw ex;
}