Рассмотрим сценарий, в котором вам нужно выполнить некоторую асинхронную работу, и вы можете запустить ее в режиме огня и забывания. Эта асинхронная работа может прослушать отмену, и вы передаете ей токен отмены, чтобы иметь возможность отменить его.
В данный момент времени мы можем принять решение запросить отмену текущей активности, используя исходный объект токена отмены, из которого мы взяли токен отмены.
Поскольку источник токена отмены реализует IDisposable
, мы должны вызвать его метод Dispose
, поскольку мы закончили с ним. Смысл этого вопроса состоит в том, чтобы точно определить , когда вы завершили работу с данным источником токена отмены.
Предположим, что вы решили отменить текущую работу, вызвав метод Cancel
для Источник токена отмены: необходимо ли ждать завершения текущей операции перед вызовом Dispose
?
Другими словами, я должен сделать это так:
class Program
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
DoSomeAsyncWork(token); // starts the asynchronous work in a fire and forget manner
// do some other stuff here
cts.Cancel();
cts.Dispose(); // I call Dispose immediately after cancelling without waiting for the completion of ongoing work listening to the cancellation requests via the token
// do some other stuff here not involving the cancellation token source because it's disposed
}
async static Task DoSomeAsyncWork(CancellationToken token)
{
await Task.Delay(5000, token).ConfigureAwait(false);
}
}
или так:
class Program
{
static async Task Main(string[] args)
{
var cts = new CancellationTokenSource();
var token = cts.Token;
var task = DoSomeAsyncWork(token); // starts the asynchronous work in a fire and forget manner
// do some other stuff here
cts.Cancel();
try
{
await task.ConfigureAwait(false);
}
catch(OperationCanceledException)
{
// this exception is raised by design by the cancellation
}
catch (Exception)
{
// an error has occurred in the asynchronous work before cancellation was requested
}
cts.Dispose(); // I call Dispose only when I'm sure that the ongoing work has completed
// do some other stuff here not involving the cancellation token source because it's disposed
}
async static Task DoSomeAsyncWork(CancellationToken token)
{
await Task.Delay(5000, token).ConfigureAwait(false);
}
}
Дополнительные сведения: код, на который я ссылаюсь, написанный внутри веб-приложения ASP. NET core 2.2, здесь я использую сценарий консольного приложения просто для упрощения моего примера.
Я обнаружил аналогичные вопросы о стековом потоке, требующие избавления от объектов-источников отмены токенов. Некоторые ответы предполагают, что в некоторых случаях избавление от этого объекта на самом деле не требуется.
Мой подход ко всему предмету IDisposable
заключается в том, что я всегда стремлюсь придерживаться открытого контракта класса, иными словами, если объект претендует на одноразовость, я предпочитаю всегда вызывать Dispose
, когда я с этим покончено Мне не нравится идея угадывать, действительно ли требуется вызов dispose, в зависимости от деталей реализации класса, которые могут измениться в будущем выпуске без документов.