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?
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.
If Bar throws an exception, it will be thrown right at the point where you call it. However, if the Task that Bar returns wraps an exception, what happens depends on your version of . NET runtime - for .
If you use a Task return type for an async method, a calling method can use an await operator to suspend the caller's completion until the called async method has finished. In the following example, the WaitAndApologizeAsync method doesn't contain a return statement, so the method returns a Task object.
Explicitly sets the return value for a task. In a DAG of tasks, a task can call this function to set a return value. Another task that identifies this task as the predecessor task (using the AFTER keyword in the task definition) can retrieve the return value set by the predecessor task.
Starting with .NET 4.6 there is a Task.FromException
method in the BCL.
There's also Task.FromCanceled
.
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;
}
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