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?

Was it helpful?

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:

  • 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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top