Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a cancelled task

I am writing a Stream class and am blocked in the ReadAsync method. Please take a look at the code, I think it can explain the situation better that I can do it with my English.

public override Task<int> ReadAsync(byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken)
{
    if (!cancellationToken.IsCancellationRequested)
    {
        return _connection.ReceiveAsync(new ArraySegment<byte>(buffer, offset, count));
    }
    return // <---------------    what here?
}

Using ILSpy I can see that other Stream classes return a cancelled task as follow:

return new Task<TResult>(true, default(TResult), TaskCreationOptions.None, cancellationToken); 

However that Task's constructor is internal and I cannot invoke it.

Google didn't help me at all.

like image 323
lontivero Avatar asked Aug 26 '14 16:08

lontivero


1 Answers

The most direct way I know to create a canceled task is to use a TaskCompletionSource:

var tcs = new TaskCompletionSource<int>();
tcs.TrySetCanceled();
return tcs.Task;

If you haven't used it before, TaskCompletionSource provides a "promise-style" task, which basically allows you to say, "Here, take this Task now, and I'll provide the result (or report an error/cancellation) whenever I'm ready." It's useful when you want to schedule/coordinate work yourself, as opposed to simply relying on a TaskScheduler.

Alternatively, if you rewrite your method using async/await, you can force the cancellation exception to automatically propagate to the result Task:

public async override Task<int> ReadAsync(
    byte[] buffer,
    int offset,
    int count,
    CancellationToken cancellationToken)
{
    cancellationToken.ThrowIfCancellationRequested();

    return await _connection.ReceiveAsync(
        new ArraySegment<byte>(
            buffer,
            offset,
            count));
}
like image 186
Mike Strobel Avatar answered Sep 20 '22 17:09

Mike Strobel