- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 WPF C# 4.0 应用程序,用于调查未处理的异常处理。我希望代码中只有一个位置可以处理任何线程上引发的未处理的异常,无论线程是如何创建的。在我的 App.xaml.cs 文件中,我有这些未处理的异常处理程序,它们向控制台发出消息:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AppDomain.CurrentDomain.UnhandledException += this.CurrentDomain_UnhandledException;
Application.Current.DispatcherUnhandledException += this.Current_DispatcherUnhandledException;
}
void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
Console.WriteLine("Current_DispatcherUnhandledException");
e.Handled = true;
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("CurrentDomain_UnhandledException");
}
}
我有一个 WPF 窗口,上面有五个按钮,它们以五种不同的方式启动线程:任务、线程、线程池、BackgroundWorker 和 System.Threading.Timer。每次单击按钮的代码分别启动一个新任务、线程等,并在新线程上抛出 NotImplementedException。在某些情况下,异常会被捕获,而在其他情况下,异常不会被捕获。
这是我的点击处理程序,其中包含代码注释,显示是否捕获了该线程上引发的异常:
private void Button_Task_Click(object sender, RoutedEventArgs e)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
throw new NotImplementedException(); //not caught
});
}
private void Button_Thread_Click(object sender, RoutedEventArgs e)
{
var thread = new System.Threading.Thread(
new System.Threading.ParameterizedThreadStart((x) =>
{
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}));
thread.Start();
}
private void Button_ThreadPool_Click(object sender, RoutedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
new System.Threading.WaitCallback((x) =>
{
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}));
}
private void Button_BWorker_Click(object sender, RoutedEventArgs e)
{
var bg = new System.ComponentModel.BackgroundWorker();
bg.DoWork += new System.ComponentModel.DoWorkEventHandler(bg_DoWork);
bg.RunWorkerAsync();
}
private void bg_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
throw new NotImplementedException(); //not caught
}
private void Button_Timer_Click(object sender, RoutedEventArgs e)
{
var timer = new System.Threading.Timer((x) =>
{
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}, null, 0, System.Threading.Timeout.Infinite);
}
这种行为对我来说似乎不一致。为什么 Timers、Thread 对象和 ThreadPool 线程会捕获异常,而 BackgroundWorkers 和 Tasks 不会?我在代码中主要使用任务、计时器和后台工作程序,因此遇到了这种不一致问题。MSDN 是否有一些文档解释 WPF 如何处理以这五种不同方式创建的线程上的未处理异常?
编辑:我使用 Action.BeginInvoke() 尝试了第六种线程创建方法。这看起来与任务类似。代码在这里:
private void Button_Action_Click(object sender, RoutedEventArgs e)
{
Action action = () =>
{
throw new NotImplementedException();
//not caught
};
action.BeginInvoke(this.DoNothing, null);
}
private void DoNothing(object arg) { }
编辑#2:我研究了引发异常的并行循环。看起来下面两个并行循环中引发的任何异常都会被捕获:
private void Button_AsParallel_Click(object sender, RoutedEventArgs e)
{
const int loops = 20;
var list = new List<int>();
for (int i = 0; i < loops; i++)
{
list.Add(i);
}
foreach (var item in list.AsParallel().Select(s => s))
{
if (item == 15)
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
}
}
private void Button_ParallelFor_Click(object sender, RoutedEventArgs e)
{
const int loops = 100;
var list = new List<int>();
for (int i = 0; i < loops; i++)
{
list.Add(i);
}
System.Threading.Tasks.Parallel.For(0, loops, (int i) =>
{
if (list[i] == 90)
throw new NotImplementedException();
//CurrentDomain_UnhandledException caught
});
}
最佳答案
经过更多搜索和测试后,我将如何处理其他线程上引发的异常。对于未处理的异常,请确保在 Application.OnStartup() 顶部进行以下调用:
AppDomain.CurrentDomain.UnhandledException +=
this.CurrentDomain_UnhandledException;
为了创建线程,我更喜欢使用 System.Threading.Thread
, System.Threading.ThreadPool.QueueUserWorkItem
,或System.Threading.Timer
。我找到BackgroundWorker
很有用,所以我以一种更容易处理未处理异常的方式扩展了该类:
public class MyBackgroundWorker : BackgroundWorker
{
protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
throw e.Error;
else
base.OnRunWorkerCompleted(e);
}
}
我可以使用IEnumerable.AsParallel
或System.Threading.Tasks.Parallel.For
对于并行循环,因为 AppDomain.CurrentDomain.UnhandledException 也会捕获它们的异常。
我会避免Tasks
。我也会避免Action<T>
s,和Func<T>
如果我打电话 BeginInvoke
在他们。我会避免这些,因为 AppDomain.CurrentDomain.UnhandledException
没有捕获它们的异常。
关于wpf - 捕获线程、任务、计时器、ThreadPool 线程和后台工作线程上引发的 UnhandledExceptions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21141549/
我是一名优秀的程序员,十分优秀!