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