Введение
После некоторого недоумения над моим кодом я обнаружил, что исключения не обязательно распространяются через ContinueWith
:
int zeroOrOne = 1;
Task.Factory.StartNew(() => 3 / zeroOrOne)
.ContinueWith(t => t.Result * 2)
.ContinueWith(t => Console.WriteLine(t.Result))
.ContinueWith(_ => SetBusy(false))
.LogExceptions();
В этом примере строка SetBusy
"сбрасывает" цепочку исключений, поэтому исключение "деление на ноль" не видно и впоследствии взрывается на моем лице "Исключение (исключения) задачи).."
Итак... Я написал себе небольшой метод расширения (с множеством разных перегрузок, но в основном все это делает):
public static Task ContinueWithEx(this Task task, Action<Task> continuation)
{
return task.ContinueWIth(t =>
{
if(t.IsFaulted) throw t.Exception;
continuation(t);
});
}
Поиск еще немного, я наткнулся на это сообщение в блоге, где он предлагает аналогичное решение, но использует TaskCompletionSource, который (перефразированный ) выглядит следующим образом:
public static Task ContinueWithEx(this Task task, Action<Task> continuation)
{
var tcs = new TaskCompletionSource<object>();
return task.ContinueWith(t =>
{
if(t.IsFaulted) tcs.TrySetException(t.Exception);
continuation(t);
tcs.TrySetResult(default(object));
});
return tcs.Task;
}
Вопрос
Являются ли эти две версии строго эквивалентными? Или есть тонкая разница между throw t.Exception
и tcs.TrySetException(t.Exception)
?
Кроме того, делает ли тот факт, что, по-видимому, только один человек во всем Интернете, который сделал это, указывает, что мне не хватает идиоматического способа сделать это?