Как правильно отменить операцию обратного вызова для одноразового объекта?

Я работаю над переносом контроллера на асинхронный режим. Часть работы включает ожидание асинхронной отменяемой операции с одноразовым объектом с использованием токена отмены, действительного в течение всего срока действия запроса. В данном конкретном случае это WebClient.UploadStringTaskAsync(Uri uri, string data).

Я знаю правильный способ отменить асинхронные операции WebClient с помощью cancellationToken.Register(() => webClient.CancelAsync()). Однако WebClient создается в операторе using, поэтому он располагается в конце блока. В результате вызов webClient.CancelAsync() из обратного вызова по праву приводит к предупреждению «Доступ к удаленному закрытию». Я обнаружил, что CancellationToken.Register(Action callback) приводит к CancellationTokenRegistration объекту, который реализует IDisposable и отменяет регистрацию обратных вызовов при удалении. В итоге мой код выглядит так:

using (var webClient = new WebClient())
using (cancellationToken.Register(() => webClient.CancelAsync())
{
     await webClient.UploadStringTaskAsync(uri, data);
}

// cancellationToken can be cancelled later.

Я создал консольное приложение, чтобы показать, что код с тем же духом работает, и отмена токена после удаления одноразового объекта и регистрации токена не приводит к вызову обратного вызова одноразового объекта. Однако я хочу быть уверен: это правильно и безопасно?

Изменить: Полагаю, мне следует немного перефразировать свой вопрос. Какое стандартное решение для использования токена отмены для отмены асинхронной операции на одноразовом объекте, где операция поддерживает отмену только через регистрацию обратного вызова?


person Alex Q    schedule 10.05.2017    source источник
comment
Отмена токена после удаления одноразового объекта и регистрации токена не приводит к вызову обратного вызова одноразового объекта - почему вы ожидаете, что обратный вызов CancellationTokenRegistration будет вызываться в противном случае?   -  person Dai    schedule 10.05.2017
comment
@Dai Я не знаю, но я также не смог найти прямого примера, на который можно было бы положиться, и я не хочу делать предположений.   -  person Alex Q    schedule 10.05.2017
comment
Без хорошего минимального воспроизводимого примера никто не может точно сказать, что будет делать код. Слишком много возможностей. Поскольку исходный код для CancellationToken является общедоступным, вы можете проверить его самостоятельно и точно знать, что он будет делать в вашем конкретном сценарии. На ваш вопрос невозможно ответить как есть. Судя по опубликованному вами коду, кажется маловероятным, что ваш WebClient может быть удален, пока обратный вызов все еще был зарегистрирован, поскольку это снова будут правила спецификации C #. Но как узнать наверняка, что делает остальная часть кода?   -  person Peter Duniho    schedule 11.05.2017
comment
@PeterDuniho Может быть, я не совсем понял, но меня больше беспокоит общий случай и его стандартное решение: Какая наилучшая практика для отмены асинхронного метода для одноразового объекта, который не поддерживает токены отмены?   -  person Alex Q    schedule 11.05.2017
comment
Вопросы, имеющие форму Какая лучшая практика ... практически всегда либо слишком общие, в основном основанные на мнении, либо (чаще всего) и то, и другое. Тем более, что одноразовые объекты, не поддерживающие токены отмены, имеют множество других механизмов отмены. Это просто зависит от объекта.   -  person Peter Duniho    schedule 11.05.2017
comment
Я не понимаю ваш отредактированный вопрос. Объект, который вы используете в качестве примера, WebClient, сам по себе не использует обратный вызов для отмены. Я думаю, что, возможно, вы имеете в виду, что для отмены с помощью CancelToken требуется регистрация обратного вызова, но это совсем не ясно из того, что вы на самом деле написали, и, безусловно, есть другие механизмы, которые можно использовать.   -  person Peter Duniho    schedule 11.05.2017


Ответы (1)


Это правильно и безопасно?

да.

Какое стандартное решение для использования токена отмены для отмены асинхронной операции на одноразовом объекте, где операция поддерживает отмену только через регистрацию обратного вызова?

В идеале операции принимают CancellationToken напрямую. В этом случае подход, который у вас уже есть, подойдет.

person Stephen Cleary    schedule 11.05.2017