Task.ContiueWith 内部发生处理异常

Handling exception occured inside Task.ContiueWith

我正在研究 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());
}

but when exception occurred in second action(success) they are ignored and nothing happens

因为您没有将代码包装在 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);
    }
}