C # Бросить OperationCanceledException изнутри CancellationToken.Register - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть длительная операция, которую я хочу отменить, скажем, через 5 секунд.К сожалению, опрос для IsCancellationRequested невозможен (длинная история).

Я использовал приведенный ниже код, чтобы вызвать исключение OperationCanceledException внутри обратного вызова отмены.Я хотел перехватить исключение в главном потоке и обработать его, чтобы полностью выйти из приложения.

Это не работает должным образом, так как это приводит к необработанному исключению, и приложение не завершает работу корректно.

Любая помощь приветствуется.Спасибо!

    void TestTimeOut()
    {
        var cts = new CancellationTokenSource();
        cts.CancelAfter(5000);

        try
        {
            var task = Task.Run(() => LongRunningOperation(cts.Token));
            task.ContinueWith(t => Console.WriteLine("Operation cancelled"), TaskContinuationOptions.OnlyOnFaulted);
            task.Wait();
        }
        catch (AggregateException e)
        {
            //Handle
        }
    }


    void LongRunningOperation(CancellationToken token)
    {
        CancellationTokenRegistration registration = token.Register(
            () =>
            {
                throw new OperationCanceledException(token); 
            });

        using (registration)
        {
            // long running operation here
        }
    }

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

В вашем коде много нет-но-ов, но я думаю, вы просто используете его в качестве демонстрации для своей проблемы.Решение - TaskCompletionSource, моя демка тоже ужасна, слишком много слоев Task.Run (), если вы используете Async, вы должны асинхронизироваться до конца.Так что не используйте его в PRD, изучите TaskCompletionSource самостоятельно и найдите лучшее решение.

    static void LongRunningOperation(CancellationToken token)
    {
        TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
        token.Register(() => { tcs1.TrySetCanceled(token); });
        Task.Run(() =>
        {
            // long running operation here
            Thread.Sleep(10000);
            tcs1.TrySetResult(0);
        }, token);
        tcs1.Task.Wait();
    }
0 голосов
/ 20 ноября 2018

Вы ловите AggregateException, но на самом деле , бросая OperationCanceledException, который не будет пойман.

Изменен, чтобы перехватывать все типы исключений, такие как

catch (Exception ex) { ... }

для разрешения.

...