Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to use ContinueWith as a "finally" operation?

Consider a piece of code like:

private Task<string> Download()
{
    var wc = new WebClient();
    Task<string> backgroundDownload = wc.DownloadStringTaskAsync(this.Uri);
    // Make sure the WebClient is disposed no matter what.
    backgroundDownload.ContinueWith((downloadTask) => { wc.Dispose(); });
    return backgroundDownload;
}

Can I be certain that the WebClient.Dispose() call occurs and that any exception produced is rethrown to the caller as if there was no call to ContinueWith?

Can clients observe this ContinueWith? (e.g. will later calls to ContinueWith remove the Dispose call?)

like image 308
Billy ONeal Avatar asked Sep 23 '14 21:09

Billy ONeal


People also ask

When should I use task ContinueWith?

The ContinueWith function is a method available on the task that allows executing code after the task has finished execution. In simple words it allows continuation. Things to note here is that ContinueWith also returns one Task. That means you can attach ContinueWith one task returned by this method.

What does calling task ContinueWith () do?

ContinueWith(Action<Task>) Creates a continuation that executes asynchronously when the target Task completes.

What is Task continuation?

A continuation task (also known just as a continuation) is an asynchronous task that's invoked by another task, known as the antecedent, when the antecedent finishes.


1 Answers

With the code that you have you can be certain that the continuation will be fired regardless of whether or not the code completed successfully, was cancelled, or throws an exception.

The one potential problem with the solution that you have is that other continuations can potentially run, before, during, or after the web client is disposed. If you don't have a problem with other continuations running before this cleanup runs then what you have is fine. If that's a problem then you'll need to return the continuation, not the original task, but you'll also need to propagate the result (and exceptions/cancellation) correctly. The use of async makes all of this way easier:

private async Task<string> Download()
{
    using(var wc = new WebClient())
      return await wc.DownloadStringTaskAsync(this.Uri);
}
like image 187
Servy Avatar answered Nov 14 '22 21:11

Servy