Существует несколько способов использования интерфейса IDisposable
в экосистеме .NET.Я хочу показать двум из них, которые особенно актуальны в многопоточном / асинхронном использовании.
Reactive Extensions
При подписке на наблюдаемый объект IDisposable
возвращается.Здесь интерфейс служит триггером отмены.Нет привязки к потоку, и он может быть вызван в любое время.Реализация обещает отмену с максимальным усилием, но не дает никаких гарантий, когда отмена наконец произойдет.Это означает, что после вызова Dispose
подписка может еще некоторое время оставаться активной.
IAsyncEnumerator
В следующем интерфейсе IAsyncEnumerable
вы сможете передать токен отменыпри получении перечислителя.Перечислитель реализует IAsyncDisposable
и должен быть утилизирован.Перечислитель не обязательно должен быть потокобезопасным, т. Е. Ему не разрешено вызывать DisposeAsync
, пока еще выполняется вызов другого метода интерфейса или возвращенной задачи.Если вы хотите остановить перечисление, вы должны использовать токен отмены.
Заключение
Важно различать отмену и очистку ресурса.В вашем случае вы также можете использовать токен отмены.Поскольку у вас уже есть все, что связано с вызовом метода, вы можете альтернативно добавить метод Cancel
.Если вам нужно сейчас, когда ваш загрузчик действительно завершает работу, вы можете реализовать интерфейс IAsyncDisposable
:
public void Cancel() => ...;
public async ValueTask DisposeAsync()
{
// Cancel();
await Task.WhenAll(_runningTasks.ToArray());
}
Если хотите, вы можете вызвать Cancel
из метода DisposeAsync
.Я не уверен, есть ли лучшая практика по этому поводу.Я бы не стал звонить туда Cancel
, потому что это дает вам или вашим пользователям API больше возможностей.Обратите внимание, что интерфейс IAsyncDisposable
будет поставляться только с Netstandard 2.1.Это не должно помешать вам, однако, использовать этот шаблон прямо сейчас.