Этот шаблон является удобным способом убедиться, что CancellationTokenRegistration.Unregister()
вызывается автоматически. Он часто используется Стивеном Тубом в его блогах Parallel Programming with .NET, например. here.
Я понимаю, что вы должны убедиться, что вы Утилизировать в IDisposable, но почему делает это даже реализует IDisposable? какие ресурсы у него есть релиз? Единственные методы, которые он считает равенством.
ИМО, лучший ответ на этот вопрос можно найти в .NET 4 Cancellation Framework сообщение от Microsoft Майк Лиддел:
Когда обратный вызов зарегистрирован в CancellationToken
, ток потока ExecutionContext
захватывается, так что обратный вызов будет запущен с тем же самым контекстом безопасности. Захват контекста синхронизации текущего потока может быть запрошен при перегрузке ct.Register()
, если требуется. Callbacks обычно хранятся, а затем запустить, когда аннулирование испрашивается, но если обратный вызов зарегистрирован после отмены была предложена, обратный вызов будет запускается сразу на текущем потоке, или через Send()
на текущем SynchronizationContext
, если это применимо.
Когда обратный вызов зарегистрирован на CancellationToken
, возвращенный объект является CancellationTokenRegistration
. Это легкий структурный тип , который равен IDiposable
, и избавление от этого объекта регистрации вызывает отмену регистрации . Гарантируется, что после возврата метода Dispose()
зарегистрированный обратный вызов не будет выполняться ни , ни в дальнейшем. Следствием этого является то, что CancellationTokenRegistration.Dispose()
должен блокироваться, если в данный момент выполняется обратный вызов . Следовательно, все зарегистрированные обратные вызовы должны быть быстрыми , а не блокировать какую-либо значительную продолжительность.
Другим важным документом Майка Лидделла является "Using Cancellation Support in .NET Framework 4" (UsingCancellationinNET4.pdf).
Обновлено, это поддающееся проверке here in the Reference Source.
Важно также отметить, что обратный вызов отмены регистрации зарегистрирован на CancellationTokenSource
, а не на CancellationToken
.Таким образом, если CancellationTokenRegistration.Dispose()
не имеет корректной области, регистрация будет оставаться активной в течение срока действия родительского объекта CancellationTokenSource
. Это может привести к неожиданному обратного вызова, когда объем асинхронной операции закончена, например .:
async Task TestAsync(WebClient wc, CancellationToken token)
{
token.Register(() => wc.CancelAsync());
await wc.DownloadStringAsync(new Uri("http://www.hamster.com"));
}
// CancellationTokenSource.Cancel() may still get called later,
// in which case wc.CancelAsync() will be invoked too
Таким образом, важно, чтобы объем одноразовой CancellationTokenRegistration
с using
(или вызвать CancellationTokenRegistration.Dispose()
явно с try/finally
).
Это утилизация злоупотреблений, вместо этого он должен иметь метод Unregister(). –
@HansPassant: будет ли это «злоупотребление» или нет, зависит от того, выполняется ли просмотр «IDisposable.Dispose» как существующего с целью очистки ресурсов или для обеспечения того, чтобы что-то, что нужно сделать, выполняется (очистка ресурсов является доминирующим типом «необходимого действия», но не единственным). – supercat
@HansPassant - Он также широко используется в asp.net MVC. Я не думаю, что это злоупотребление, если авторы карьеры делают это сами. –