Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simple way to return a task with an exception?

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?

like image 545
Matt Johnson-Pint Avatar asked Mar 25 '14 00:03

Matt Johnson-Pint


People also ask

How do you throw a task exception?

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.

What happens if a task throws an exception?

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 .

How do I return a task in async?

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.

How do you set a return value in a task?

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.


2 Answers

Starting with .NET 4.6 there is a Task.FromException method in the BCL.

There's also Task.FromCanceled.

like image 110
Drew Noakes Avatar answered Sep 21 '22 20:09

Drew Noakes


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;
}
like image 33
noseratio Avatar answered Sep 22 '22 20:09

noseratio