Ответ 1
Я понимаю, что return Task.FromResult(foo) является простым сокращение для... [
TaskCompletionSource.SetResult
].
Собственно, Task.FromResult
не использует TaskCompletionSource
, его реализация намного проще.
Есть ли какой-то эквивалент для задачи, которая возвращает состояние исключения?
Я считаю, что TaskCompletionSource
будет лучшим вариантом для этого. Вы также можете сделать что-то вроде этого:
static Task FromExAsync(Exception ex)
{
var task = new Task(() => { throw ex; });
task.RunSynchronously();
return task;
}
Исключение не будет распространяться вне возвращаемого task
, пока не будет обнаружено через await task
или task.Wait()
, что должно быть желательным поведением.
Обратите внимание, что если исключение, переданное в FromExAsync
, является активным исключением (т.е. уже было выброшено и обнаружено в другом месте), повторное бросание его таким образом потеряет текущую трассировку стека, а информация Watson будет храниться внутри исключения. Существует два способа борьбы с ним:
- Оберните исключение с помощью
AggregateException
. Это сделает исходное исключение доступным какAggregateException.InnerException
:
static Task FromExAsync(Exception ex)
{
var task = new Task(() => { throw new AggregateException(ex); });
task.RunSynchronously();
return task;
}
- Используйте
ExceptionDispatchInfo.Capture
для потока активного состояния исключения:
static Task FromExAsync(Exception ex)
{
var ei = System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex);
var task = new Task(() => { ei.Throw(); });
task.RunSynchronously();
return task;
}
Наконец, возможно, самый простой, но худший вариант (из-за служебных данных конечного автомата и предупреждения компилятора) заключается в том, чтобы выкинуть из метода async
:
static async Task FromExAsync(Exception ex)
{
throw ex;
}