你的位置:首页 > ASP.net教程

[ASP.net教程]WPF 程序 处理未捕获异常,和程序莫名终止说拜拜


百密一疏的Bug很难避免,没有谁能保证,我的程序永远 0 BUG;

 

突然接手一个很庞大的项目,在项目运行期间会莫名异常结束,异常极难重现,还找不出BUG代码,代码太多了。

这个时候就需要把程序中发生的BUG记录下来,知道哪里BUG了,才好下次更新解决。

把所有代码全部加 try catch ?  那就怀孕了,真的搞大了。

 

未捕获的异常处理:

一:C# 在 Application 类中提供了 DispatcherUnhandledException 事件,用于处理UI线程上未捕获的异常

public partial class App : Application{  protected override void OnStartup(StartupEventArgs e)  {    DispatcherUnhandledException += App_DispatcherUnhandledException;    base.OnStartup(e);  }  void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)  {    //e.Exception  发生的异常    //e.Handled   是否已处理异常事件  }}

但是 DispatcherUnhandledException 捕获不了 非UI线程上发生的异常

 

二:C# 在 AppDomain 类中提供了 UnhandledException 事件,用于捕获应用程序域中发生的异常

AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e){  MessageBox.Show("Unhandle");//MessageBox.Show((e.ExceptionObject == null ? "Null" : e.ExceptionObject.GetType().Name),  //  "CurrentDomain_UnhandledException:");}

这样就能捕获应用程序域中发生的异常,当然,包括UI线程和非UI线程异常,如果你有创建应用程序域的需求,创建完成,再绑定下事件即可。

但是AppDomain.UnhandledException 事件没有提供 终止异常,也就是说,异常发生了,你没捕获,这里通知一下,但是该程序结束还得结束。

 

在这里要特别提到官方封装的 Delegate.BeginInvoke();

"已知:"在异步函数中发生了异常并且没处理:

"求解:"

1.没调用 Delegate.EndInvoke() 函数:

    终止执行。 程序不会挂掉,异常丢弃。这是种很隐蔽的BUG,很难发现。

    AppDomain.UnhandledException 事件不会通知发生了异常,这里要特别注意。

public void Hello(){  World();  Load();}public void World(){
throw new Exception();
}public void Load(){ MessageBox.Show("Suc");}var action = new Action(Hello);action.BeginInvoke(null, null);

像这种示例,如果在World() 方法中发生了异常,线程会立即终止,Load() 函数就不会执行,程序也不会终止。

一个函数没有执行,也许就会导致很严重的异常,还很难发现。

 

2.调用了 Delegate.EndInvoke() 函数:

    异常抛出, 程序挂掉。

    AppDomain.UnhandledException 事件会通知发生了异常

 

这里也许会有个需求,如果我想处理 AppDomain.UnhandledException 事件中的异常怎么办?程序挂了太恶心了。

我们来继续扩展这个框架

解决在非UI线程中访问UI 异常的小方法

/// <summary>/// 委托 扩展类/// </summary>public static class DelegateExtension{
/// <summary> /// 可以被捕获异常的异步调用 /// </summary> /// <param name="dele"></param> public static void UnsafeBeginInvoke(this Delegate dele) { var action = new Action(() => { dele.DynamicInvoke(); }); action.BeginInvoke(new AsyncCallback((ar) => { try { action.EndInvoke(ar); } catch (Exception ex) { App.Current.Dispatcher.BeginInvoke(new Action(() => { throw ex; })); } }), null); }}

有点不伦不类哈,厄。把异常推送到UI线程上抛出,让Application.DispatcherUnhandledException 事件处理

 

其它:C# 在 TaskScheduler 类中提供了 UnobservedTaskException 事件,用于捕获 Task 异步异常

 

求评论,求吐槽,求求你^v^