Rethrowing previous exception inside ContinueWith

Viewed 4911

###Intro

After puzzling over my code for a while, I discovered that exceptions don't necessarily propagate through ContinueWith:

int zeroOrOne = 1;
Task.Factory.StartNew(() => 3 / zeroOrOne)
    .ContinueWith(t => t.Result * 2)
    .ContinueWith(t => Console.WriteLine(t.Result))
    .ContinueWith(_ => SetBusy(false))
    .LogExceptions();

In this example, the SetBusy line 'resets' the chain of exceptions, so the divide by zero exception isn't seen and subsequently blows up in my face with "A Task's exception(s) were not observed..."

So... I wrote myself a little extension method (with tons of different overloads, but basically all doing this):

public static Task ContinueWithEx(this Task task, Action<Task> continuation)
{
     return task.ContinueWith(t =>
     {
         if(t.IsFaulted) throw t.Exception;
         continuation(t);
     });
}

Searching around a bit more, I came across this blog post, where he proposes a similar solution, but using a TaskCompletionSource, which (paraphrased) looks like this:

public static Task ContinueWithEx(this Task task, Action<Task> continuation)
{
     var tcs = new TaskCompletionSource<object>();
     task.ContinueWith(t =>
     {
         if(t.IsFaulted) tcs.TrySetException(t.Exception);
         continuation(t);
         tcs.TrySetResult(default(object));
     });
     return tcs.Task;
}

###Question Are these two versions strictly equivalent? Or is there a subtle difference between throw t.Exception and tcs.TrySetException(t.Exception)?

Also, does the fact that there's apparently only one other person on the whole internet who's done this indicate that I'm missing the idiomatic way of doing this?

1 Answers
Related