Equivalent of ContinueWith(delegate, CancellationToken) with await continuation
.net, async-await, c#
Solution
The following should do it, albeit it looks a bit awkward:
private Task LongRunningTask = /* Something */;
private void DoSomethingMore() { }
public async Task IndependentlyCancelableSuccessorTask(
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(() => tcs.TrySetCanceled()))
await Task.WhenAny(LongRunningTask, tcs.Task);
cancellationToken.ThrowIfCancellationRequested();
DoSomethingMore();
}
[UPDATE] Following svick's suggestion, here it is shaped as a helper, based on Stephen Toub's Implementing Then with Await pattern:
public static class TaskExt
{
/// <summary>
/// Use: await LongRunningTask.Then(DoSomethingMore, cancellationToken)
/// </summary>
public static async Task Then(
this Task antecedent, Action continuation, CancellationToken token)
{
await antecedent.When(token);
continuation();
}
/// <summary>
/// Use: await LongRunningTask.When(cancellationToken)
/// </summary>
public static async Task When(
this Task antecedent, CancellationToken token)
{
token.ThrowIfCancellationRequested();
var tcs = new TaskCompletionSource<Empty>();
using (token.Register(() => tcs.TrySetCanceled()))
await Task.WhenAny(antecedent, tcs.Task);
token.ThrowIfCancellationRequested();
}
struct Empty { };
}
Perhaps, the first `ThrowIfCancellationRequested()` is redundant, but I haven't thoroughly considered all edge cases.
Problem
I have that situation: ``` private Task LongRunningTask = /* Something */; private void DoSomethingMore(Task previousTask) { } public Task IndependentlyCancelableSuccessorTask(CancellationToken cancellationToken) { return LongRunningTask.ContinueWith(DoSomethingMore, cancellationToken); } ``` In particular, the behavior that interests me here is detailed in MSDN's page about Continuation Tasks in the following terms: A continuation goes into the `Canceled` state in these scenarios: - [...] - When the continuation was passed a `System.Threading.CancellationToken` as an argument and the `IsCancellationRequested` property of the token is `true` before the continuation runs. In such a case, the continuation does not start and it transitions to the `Canceled` state. The code above works. However, I am in the process of converting as many as possible of my continuations to using the `await` keyword. Is there an equivalent using `await` that would allow the continuation to be canceled before the awaited task completes?