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:
- Wrap the exception with
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;
}
- Use
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;
}