【问题标题】:Can't catch exception from ThrowIfCancellationRequested()无法从 ThrowIfCancellationRequested() 捕获异常
【发布时间】:2019-01-22 16:36:09
【问题描述】:

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(); 并按照彼得的建议,lambda 内的 Throw 现在抛出异常,我放在它上面的 try catch 块也不起作用,但是外面的 try catch lambda 捕获了异常。代码如下:

    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");
        }
    }

这对我有点用 :) 但还是想了解这里发生了什么

【问题讨论】:

  • 未处理的异常具体是什么?
  • OperationCanceledException 精确
  • 哦,我没注意到你有两个ThrowIfCancellationRequested 电话。是第二个抛出异常吗? Xamarin.Forms.Device.StartTimer 看起来像是一个即发即弃的函数,因此其委托的异常不会传播到外部方法。
  • 您确定异常是在您拥有catch 的线程中引发的吗?我想说,问题是,你需要在另一个线程中捕获异常(因为我看到那里有asyncTaks.RunStartTimer
  • 如果你捕获CancellationException inside lambda 传递给StartTimer 并返回 false,那应该可以解决它。

标签: c# xamarin.forms cancellation


【解决方案1】:

您正在传递 StartTimer 一个 lambda,它会在取消发生时抛出 CancellationException,但此异常不一定会在 StartTimerTimedSync 的范围内触发。

我的猜测是,因为我不使用 Xamarin,所以运行 lambda 的计时器代码会在单独的任务中看到异常,并将其提升为应用程序故障。

如果您在 lambda 中捕获 CancellationException 并返回 false,这应该具有停止计时器的预期效果而不将异常传播到 Xamarin 计时器代码。

请注意,对ct.ThrowIfCancellationRequested() 的直接调用会被TimedSync 捕获并命中你的catch 块。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 2021-10-09
    • 2012-01-06
    • 1970-01-01
    相关资源
    最近更新 更多