Given a cancellation token, I'd like to create an awaitable task out of it, which is never complete but can be cancelled. I need it for a pattern like this, which IMO should be quite common:
async Task DoStuff(Task t, CancellationToken ct)
{
// t was made from TaskCompletionSource,
// both t and ct are beyond my control
Task t2 = TaskFromCancellationToken(ct);
await Task.WhenAny(t, t2);
// do stuff
}
The best idea I've got so far is this:
Task TaskFromCancelationToken(CancellationToken ct)
{
return Task.Delay(Timeout.Infinite, ct);
}
Is there a better way to make this logic happen?
It's not extremely common, but it's common enough to be part of my AsyncEx library. I use something like this:
public static Task AsTask(this CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<object>();
cancellationToken.Register(() => tcs.TrySetCanceled(),
useSynchronizationContext: false);
return tcs.Task;
}
Update: These days, I recommend using something like CancellationTokenTaskSource, which properly handles all lifetimes with no possibility of resource leaks.
Task.Delay(Timeout.Infinite, cancellationToken)
The answer you suggest in your question is the best solution to my knowledge. Here's why:
The Task.Delay approach is heavily used by a lot of folks as per my knowledge, and is also recommended on Microsoft blogs. MSDN Example.
Why write code (including tests) yourself leveraging TaskCompletionSource for converting a cancellation token to a task? It is preferable to leverage the standard libraries instead of reinventing the wheel; they are more likely to be bug free than your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With