Не удается поймать исключение из ThrowIfCancellationRequested () - PullRequest
0 голосов
/ 22 января 2019

Welp, у меня есть этот код:

    public static async Task TimedSync (CancellationToken ct)
    {
        try {
            if (ct.IsCancellationRequested)
                ct.ThrowIfCancellationRequested();
            await Task.Run(async () => await UP.Sincronizacao.SyncDB(true));
            Xamarin.Forms.Device.StartTimer(TimeSpan.FromMinutes(1), () => {
                if (ct.IsCancellationRequested)
                    ct.ThrowIfCancellationRequested();
                Task.Run(async () => await UP.Sincronizacao.SyncDB(false));
                return true;
            });
        } catch (OperationCanceledException) {
            await Current.MainPage.DisplayAlert("Got it", "Good", "ok");
        } catch (Exception e) {
            await Current.MainPage.DisplayAlert("Oops", e.Message, "dismiss");
        }
    }

В этот момент приложение просто падает, и при отладке я обнаружил, что исключение, выданное ThrowIfCancellationRequested(), не обработано.

Редактировать: Хорошо, что-то действительно странное произошло, я удалил первый if(ct.IsCancellationRequested) ct.ThrowIfCancellationRequested(); и последовал совету Питера. Бросок внутри лямбды теперь вызывает исключение, блок try catch, который я на него наделил, тоже не сработал, но try catchснаружи лямбда поймала исключение.Вот код:

    public static async Task TimedSync (CancellationToken ct)
    {
        try {
            await Task.Run(async () => await UP.Sincronizacao.SyncDB(true));
            Xamarin.Forms.Device.StartTimer(TimeSpan.FromMinutes(1), () => {
                try {
                    if (ct.IsCancellationRequested)
                        ct.ThrowIfCancellationRequested();
                    Task.Run(async () => await UP.Sincronizacao.SyncDB(false));
                    return true;
                } catch (OperationCanceledException) {
                    return false;
                }
            });
        } catch (OperationCanceledException) {
            await Current.MainPage.DisplayAlert("Got it", "Good", "ok");
        } catch (Exception e) {
            await Current.MainPage.DisplayAlert("Oops", e.Message, "dismiss");
        }
    }

Это вроде как работает для меня :) Но все же хотелось бы понять, что здесь происходит

1 Ответ

0 голосов
/ 22 января 2019

Вы передаете StartTimer лямбду, которая выдает CancellationException, когда происходит отмена, но это исключение не обязательно срабатывает внутри StartTimer или области действия TimedSync.

Полагаю, поскольку я не использую Xamarin, код таймера, на котором запускается ваша лямбда, видит исключение в отдельной задаче и преобразует его в сбой приложения.

Если вы поймаете CancellationException в лямбде и вернете false, это должно иметь желаемый эффект остановки таймера без распространения исключения для кода таймера Xamarin.

Обратите внимание, что прямой вызов ct.ThrowIfCancellationRequested() будет перехватываться внутри TimedSync и попадать в ваш блок catch.

...