gpt4 book ai didi

c# - 如何将线程异常传播回应用程序异常处理程序

转载 作者:行者123 更新时间:2023-11-30 22:16:24 24 4
gpt4 key购买 nike

http://msdn.microsoft.com/en-us/magazine/gg598924.aspx

Why exceptions are not propagated by WPF Dispatcher.Invoke?

How can I allow Task exceptions to propagate back to the UI thread?

在下面的代码中,我需要传播任务中抛出的异常,并将它们的延续返回到 ui 线程,在那里它们将由 LogException 处理。如果我需要在沿线的某处重新抛出异常,那对我来说很好。什么都行。我怎么做?我引用了一些与我的问题类似的问题,但我没有看到与我的应用相关的答案。
编辑 3: 发布了一个简化的示例

编辑 2:看到这个: http://msdn.microsoft.com/en-us/library/dd997415(v=vs.100).aspx

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
FireAndForget();
WaitOnTask();
}

private void FireAndForget()
{
Task t1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
throw new Exception("boo");
});

Task c1 = t1.ContinueWith((t) =>
{
// The app global exception handler will not catch this.

}, TaskContinuationOptions.OnlyOnFaulted);

//MessageBox.Show("Task is running");
}


private void WaitOnTask()
{
Task t1 = Task.Factory.StartNew(() =>
{
throw new Exception("boo");
});

try
{
t1.Wait();
}
catch (Exception ex)
{
// The app global exception handler will catch this:
throw new Exception("Task", ex);
}
}
}



public partial class App : Application
{
public App()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Current.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException);
//System.Threading.Tasks.TaskScheduler.UnobservedTaskException += new EventHandler<System.Threading.Tasks.UnobservedTaskExceptionEventArgs>(TaskScheduler_UnobservedTaskException);
}

void TaskScheduler_UnobservedTaskException(object sender, System.Threading.Tasks.UnobservedTaskExceptionEventArgs e)
{
LogException(e.Exception);
}

void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
LogException(e.Exception);
}

void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
LogException(e.ExceptionObject as Exception);
}

private void LogException(Exception ex)
{
// log it
string error = "This app has encountered an unexpected error . The error message is:" + Environment.NewLine + ex.Message + Environment.NewLine;
Exception tmp = ex.InnerException;

while (tmp != null)
{
error += "Inner exception is: " + Environment.NewLine + tmp.Message + Environment.NewLine;
tmp = tmp.InnerException;
}

error += "Please press OK to exit.";
MessageBox.Show(error, "Error");
Environment.Exit(-1);
}
}

最佳答案

当您使用 StartNewContinueWith 时,任何异常都会放在返回的 Task 上。

编码异常有两个问题:

  1. Task.Exception 将您的异常包装在 AggregateException 中。
  2. 当您稍后抛出异常时(例如,在另一个线程上),原始调用堆栈将丢失。

对于第一个问题,有些人使用FlattenHandle 成员直接与AggregateException 一起工作。我更喜欢通过处理 Task.Exception.InnerException 而不是 Task.Exception 来解包异常。

对于第二个问题,有些人通过将其包装在另一个异常中来解决它,但我采用了另一种方法。 .NET 4.5 引入了 ExceptionDispatchInfo,这是执行此操作的正确方法。在 .NET 4.0 中,你可以破解这样的东西:

public static Exception Rethrow(this Exception ex)
{
typeof(Exception).GetMethod("PrepForRemoting",
BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(ex, new object[0]);
throw ex;
}

关于c# - 如何将线程异常传播回应用程序异常处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17411297/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com