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?

Original source

Related problems