正如其他人已经提到的那样,没有干净的方法可以实现您的要求。异步编程模型中没有取消的概念;因此,它不能通过FromAsync
转换器进行改造。
但是,您可以Task
为包装异步操作的 引入取消。这不会取消底层操作本身——你NetworkStream
仍然会继续从套接字读取所有请求的字节——但它会允许你的应用程序像操作被取消一样做出反应,立即OperationCanceledException
从你那里抛出一个await
(并执行任何注册的任务延续) . 底层操作的结果一旦完成,将被忽略。
这是一个辅助扩展方法:
public static class TaskExtensions
{
public async static Task<TResult> HandleCancellation<TResult>(
this Task<TResult> asyncTask,
CancellationToken cancellationToken)
{
// Create another task that completes as soon as cancellation is requested.
// http://stackoverflow.com/a/18672893/1149773
var tcs = new TaskCompletionSource<TResult>();
cancellationToken.Register(() =>
tcs.TrySetCanceled(), useSynchronizationContext: false);
var cancellationTask = tcs.Task;
// Create a task that completes when either the async operation completes,
// or cancellation is requested.
var readyTask = await Task.WhenAny(asyncTask, cancellationTask);
// In case of cancellation, register a continuation to observe any unhandled
// exceptions from the asynchronous operation (once it completes).
// In .NET 4.0, unobserved task exceptions would terminate the process.
if (readyTask == cancellationTask)
asyncTask.ContinueWith(_ => asyncTask.Exception,
TaskContinuationOptions.OnlyOnFaulted |
TaskContinuationOptions.ExecuteSynchronously);
return await readyTask;
}
}
这是一个使用扩展方法将操作视为在 300 毫秒后取消的示例:
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromMilliseconds(300));
try
{
int bytesRead =
await Task<int>.Factory.FromAsync(this.stream.BeginRead, this.stream.EndRead, buffer, 0, buffer.Length, null)
.HandleCancellation(cts.Token);
}
catch (OperationCanceledException)
{
// Operation took longer than 300ms, and was treated as cancelled.
}