正在处理Task.ContinueWith内部发生的异常

本文关键字:异常 内部 ContinueWith 处理 Task | 更新日期: 2023-09-27 17:59:41

我正在研究wpf,我已经编写了以下代码,以显示从web服务获取数据时发生的异常。

有两种操作方法,第一种是调用远程服务,第二种是在得到结果时更新UI对象。

当第一个操作(初始)中发生异常时,我正确地获得了异常框,但当第二个操作(成功)中出现异常时,它们被忽略,什么都没有发生。事件断点未在continue with的最后一行命中。

我想知道发生了什么以及最好的解决方案。这种类型的异常不能全局处理吗?

private void ExecuteSafely(string message, Action intial, Action successAction)
{
    var task = Task.Factory.StartNew(intial);
    task.ContinueWith(t =>
    {
        if (t.Exception != null)
        {
            HandleException(t.Exception);
        }
        else
        {
            successAction.Invoke();
        }
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

正在处理Task.ContinueWith内部发生的异常

但当第二个操作(成功)中出现异常时,它们将被忽略什么也没发生

因为您没有将代码包装在try-catch块中,因此该异常不会被处理,而是被您的继续任务所吞噬。

要抓住它,请进行包装:

private void ExecuteSafely(string message, Action initial, Action successAction)
{
    var task = Task.Factory.StartNew(initial).ContinueWith(t =>
    {
        if (t.Exception != null)
        {
            HandleException(t.Exception);
        }
        else
        {
            try
            {
               successAction();
            }
            catch (Exception e)
            { 
                // Handle your exception.
            }
        }
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

如果您使用的是.NET 4.0,则吞噬的异常最终将在Task的定稿过程中抛出。

如果您使用的是.NET 4.5,async-await将不那么冗长:

private async Task ExecuteSafelyAsync(string message, 
                                      Action initial, 
                                      Action successAction)
{
    try
    {
        var task = await Task.Run(initial);
        successAction();
    }
    catch (Exception e)
    {
        // You get here if either Task.Run or successAction throws
    }
}

当你调用它时:

await ExecuteSafelyAsync("hello", initial, success);    

successAction抛出异常时,UI线程无法捕获异常,因为successAction没有在UI线程上调用。

如果你在.net 4.5上工作,我认为你应该使用async/await,比如:

private async void ExecuteSafely(string message, Action intial, Action successAction)
{
    try
    {
        await Task.Factory.StartNew(intial);
        successAction.Invoke();
    }
    catch (Exception e)
    {
        HandleException(e);
    }
}