`

利用委托机制处理.NET中的异常

阅读更多

转自 terrylee.cnblogs.com

概述

在.NET中,可以轻松的通过try-catch块来捕获异常。为了防止在应用程序中出现未处理的异常,可以通过添加一个全局的异常处理函数,如果是多线程的处理,还必须考虑除了主线程之外的工作线程中的异常处理办法,这里用委托机制来实现。


主线程的异常处理

使用Application对象中的ThreadException属性设置一个delegate来捕获所有的未处理的主线程中出现的异常。注意这个全局异常处理程序,只能捕获到主线程中的异常,对于我们自己添加的工作线程、辅助线程的异常是捕获不到的。

在应用程序入口添加全局异常处理:
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
    ///添加主线程的全局异常处理
    Application.ThreadException += new ThreadExceptionEventHandler(
        MainUIThreadExceptionHandler);

    Application.Run(new Form1());
}
 处理程序:
public static void MainUIThreadExceptionHandler(Exception ex)
{
    MainUIThreadExceptionHandler(null, new ThreadExceptionEventArgs(ex));
}

/// <summary>
/// 主线程全局异常信息的处理
/// </summary>
/// <param name="sender"></param>
/// <param name="t"></param>
public static void MainUIThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
{
    MessageBox.Show(
        "应用程序发生了如下的异常信息"
        + ":" + (char) 13
        + (char) 13 + e.Exception.Message
        + (char) 13 + (char) 13
        + "请于系统管理员取得联系!"
        + (char) 13 + (char) 13
        , "异常信息"
        , MessageBoxButtons.OK
        , MessageBoxIcon.Error
        , MessageBoxDefaultButton.Button1
        , MessageBoxOptions.ServiceNotification);
}
 工作线程的异常处理

编写多线程代码时,我们必须考虑在工作线程中出现的异常。在线程的入口使用try-catch块,并通过delegate将发生的异常通知给主线程。必须将异常信息通知主线程,否则应用程序不会报错,异常将会消失。

在线程入口使用try-catch块:
/// <summary>
/// 在线程的入口点加入try-catch块
/// </summary>
private void DataSave()
{
    try
    {
        CreateException();
    }
    catch (Exception e)
    {
        ///通过delegate转向工作线程的异常处理
        new WorkerThreadExceptionHandlerDelegate(
            WorkerThreadExceptionHandler).BeginInvoke(e
            , null
            , null);
    }
}
 工作线程异常的处理:
/// <summary>
/// 声明工作线程的delegate
/// </summary>
public delegate void WorkerThreadExceptionHandlerDelegate(Exception e);

/// <summary>
/// 工作线程的异常处理
/// </summary>
/// <param name="e"></param>
public void WorkerThreadExceptionHandler(Exception e)
{
    ///添加其他的处理代码

    ///通知全局异常处理程序
    MainUIThreadExceptionHandler(this, new ThreadExceptionEventArgs(e));
}
 总结

对于捕获到异常,我们可以Log到文件或者数据库,但是必须保证捕获到所有的异常,以上通过委托机制实现了.NET中的主线程以及工作线程中的异常捕获。

完整的程序代码:
using System;
using System.Threading;
using System.Windows.Forms;

namespace UseDelegateException
{
    /// <summary>
    /// 功能:利用Delegate实现异常的全局处理
    /// 编写:Terrylee
    /// 日期:2005年12月10日
    /// </summary>
    public class Form1 : System.Windows.Forms.Form
    {
        private System.Windows.Forms.Button btnMainUIThread;
        private System.Windows.Forms.Button btnWorkThread;
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.Container components = null;

        public Form1()
        {
            //
            // Windows 窗体设计器支持所必需的
            //
            InitializeComponent();

            //
            // TODO: 在 InitializeComponent 调用后添加任何构造函数代码
            //
        }

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }
        #region Windows 窗体设计器生成的代码
        /// <summary>
        /// 设计器支持所需的方法 - 不要使用代码编辑器修改
        /// 此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.btnMainUIThread = new System.Windows.Forms.Button();
            this.btnWorkThread = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // btnMainUIThread
            // 
            this.btnMainUIThread.Location = new System.Drawing.Point(40, 72);
            this.btnMainUIThread.Name = "btnMainUIThread";
            this.btnMainUIThread.Size = new System.Drawing.Size(112, 48);
            this.btnMainUIThread.TabIndex = 0;
            this.btnMainUIThread.Text = "主线程异常";
            this.btnMainUIThread.Click += new System.EventHandler(this.btnMainUIThread_Click);
            // 
            // btnWorkThread
            // 
            this.btnWorkThread.Location = new System.Drawing.Point(240, 72);
            this.btnWorkThread.Name = "btnWorkThread";
            this.btnWorkThread.Size = new System.Drawing.Size(112, 48);
            this.btnWorkThread.TabIndex = 1;
            this.btnWorkThread.Text = "工作线程异常";
            this.btnWorkThread.Click += new System.EventHandler(this.btnWorkThread_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
            this.ClientSize = new System.Drawing.Size(392, 197);
            this.Controls.Add(this.btnWorkThread);
            this.Controls.Add(this.btnMainUIThread);
            this.MaximizeBox = false;
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
        }
        #endregion

        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            ///添加主线程的全局异常处理
            Application.ThreadException += new ThreadExceptionEventHandler(
                MainUIThreadExceptionHandler);

            Application.Run(new Form1());
        }

        public static void MainUIThreadExceptionHandler(Exception ex)
        {
            MainUIThreadExceptionHandler(null, new ThreadExceptionEventArgs(ex));
        }

        /// <summary>
        /// 主线程全局异常信息的处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="t"></param>
        public static void MainUIThreadExceptionHandler(object sender, ThreadExceptionEventArgs e)
        {
            MessageBox.Show(
                "应用程序发生了如下的异常信息"
                + ":" + (char) 13
                + (char) 13 + e.Exception.Message
                + (char) 13 + (char) 13
                + "请于系统管理员取得联系!"
                + (char) 13 + (char) 13
                , "异常信息"
                , MessageBoxButtons.OK
                , MessageBoxIcon.Error
                , MessageBoxDefaultButton.Button1
                , MessageBoxOptions.ServiceNotification);
        }

        /// <summary>
        /// 声明工作线程的delegate
        /// </summary>
        public delegate void WorkerThreadExceptionHandlerDelegate(Exception e);

        /// <summary>
        /// 工作线程的异常处理
        /// </summary>
        /// <param name="e"></param>
        public void WorkerThreadExceptionHandler(Exception e)
        {
            ///添加其他的处理代码

            ///通知全局异常处理程序
            MainUIThreadExceptionHandler(this, new ThreadExceptionEventArgs(e));
        }
        /// <summary>
        /// 制造异常信息,这里抛出一个除0的异常
        /// </summary>
        private void CreateException()
        {
            int a = 1;
            int b = 0;

            int c;
            c = a / b;
        }

        /// <summary>
        /// 在线程的入口点加入try-catch块
        /// </summary>
        private void DataSave()
        {
            try
            {
                CreateException();
            }
            catch (Exception e)
            {
                ///通过delegate转向工作线程的异常处理
                new WorkerThreadExceptionHandlerDelegate(
                    WorkerThreadExceptionHandler).BeginInvoke(e
                    , null
                    , null);
            }
        }

        /// <summary>
        /// 发生主线程异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMainUIThread_Click(object sender, System.EventArgs e)
        {
            ///这里出现一个异常,我们不予捕获,交由全局处理函数
            CreateException();
        }

        /// <summary>
        /// 发生工作线程异常
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnWorkThread_Click(object sender, System.EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(DataSave));
            t.Start();
        }
    }
}
 
分享到:
评论

相关推荐

    .net C# 委托 调用事件

    本教程将深入探讨C#中的委托及其在ASP.NET中的应用,特别是如何利用委托来调用事件。 一、委托的基本概念 1. **定义委托** 委托是类的一种,它定义了一种方法签名,即接受的参数类型和返回类型。你可以通过`...

    VB.NET教程中高级篇

    在VB.NET中,中高级主题通常包括但不限于面向对象编程(OOP)、异常处理、多线程、高级数据访问、文件和流操作、网络编程、反射、委托和事件、LINQ以及自定义控件和用户界面设计。下面,我们将详细探讨这些关键知识...

    vb.net 中英文对照

    此外,VB.NET支持XML集成,可以直接在代码中处理XML文档,简化了Web服务和数据交换。 VB.NET的编程模型引入了LINQ(Language Integrated Query),这是一种查询语言,允许开发者在代码中直接书写SQL风格的查询,...

    多播委托,并解决多播委托出现异常,不能迭代

    标题所提到的问题是关于如何在多播委托中处理异常,确保即使某个方法抛出异常,其他方法仍然能够执行。这通常涉及到异常处理机制,如try-catch块,以及可能的委托调用模式的调整。 下面我们将详细探讨多播委托、...

    《利用.NET框架开发应用系统》示例代码

    示例代码中可能包含C#的基础语法、类与对象、接口、继承、泛型、委托、事件、异常处理等内容。 3. **ASP.NET Web开发**:.NET框架提供了ASP.NET,用于构建动态Web应用程序。示例代码可能包括ASP.NET页面生命周期、...

    VB.NET Step By Step 系列课程(4):VB.NET中的面向对象设计(教程).zip

    在《VB.NET Step By Step (4):VB.NET中的面向对象设计》教程中,你将逐步学习如何利用这些概念来设计和实现复杂的应用程序。通过实例和练习,你将深化对VB.NET面向对象编程的理解,并能够熟练运用到实际项目中。这...

    programming .net components 2nd.rar

    3. **事件驱动编程**:.NET组件经常使用事件处理机制,书中的内容可能涉及如何定义和处理事件,以及事件委托(Delegate)和事件args(EventArgs)的使用。 4. **泛型**:自.NET 2.0以来,泛型提供了类型安全的容器...

    利用WinRar压缩与解压(VB.NET+线程).rar

    在VB.NET中,可以使用`Try...Catch`结构来捕获和处理异常。 7. **密码保护**:如果需要对压缩文件设置密码,可以通过WinRAR API中的相关函数实现。在调用`RarSetPassword`函数前,先让用户输入密码,然后将密码字符...

    .NET的一些基础知识

    在.NET中,异常处理是通过try-catch-finally语句块实现的。当发生异常时,控制流会立即跳转到相应的catch块。例如: ```csharp try { // 可能抛出异常的代码 } catch (Exception ex) { Console.WriteLine("发生了...

    Vb.Net-CallID来显示

    事件委托在VB.NET中是事件处理机制的基础。它是一种类型,用于定义事件处理函数的签名。在这个来电显示程序中,`DataReceived`事件就是通过事件委托` SerialDataReceivedEventHandler`来定义的。当事件发生时,系统...

    VB.NET中高级篇

    在VB.NET中高级篇的学习中,我们将会深入探讨.NET Framework的高级特性以及VB.NET编程的精髓,这将有助于提升你的编程技巧和项目开发能力。在这个阶段,我们将关注以下几个核心知识点: 1. **面向对象编程(OOP)**...

    vb.net中高级篇

    了解如何正确使用异常处理机制对于编写健壮的代码至关重要。 5. **Lambda表达式与LINQ**:Lambda表达式是匿名函数的一种形式,常与LINQ(Language Integrated Query)结合使用,简化数据查询。学习如何利用LINQ进行...

    VC++.NET(2008)课程设计经典案例.rar

    8. **事件和委托**:掌握.NET中的事件处理机制,包括委托的使用和事件的订阅与发布。 9. **界面设计**:如果涉及到Windows Forms或WPF,会涵盖用户界面的设计和交互,如控件的使用、布局管理、事件处理等。 10. **...

    Visual Basic.NET线程参考手册

    VB.NET提供了Try...Catch...Finally结构来处理异常,确保即使在异常情况下也能执行必要的清理操作。此外,使用Async/Await关键字进行异步编程可以简化异常处理,并且有助于防止死锁。 七、线程池与后台线程 线程池...

    张子阳《.NET之美》样章 - C#中的委托和事件(完整)

    例如,`EventHandler`委托和`EventArgs`类是.NET框架中最常用的事件处理机制之一。 **示例:** 1. **定义事件**: ```csharp public event EventHandler&lt;MyEventArgs&gt; CustomEvent; ``` 2. **触发事件**: ...

    Microsoft.NET.框架程序设计源码

    文件如`11-Events`和`17-Delegates`深入讲解了事件和委托的使用,这是C#中处理异步操作和回调的重要机制。 2. **属性(Properties)**:`10-Properties`涵盖了.NET中对象属性的定义和使用,它是封装数据并提供访问...

    C#.NET 编程经典-从VB6.0到VC#.NET 快速进阶

    异常处理是任何编程语言中不可忽视的部分,C#.NET也不例外。书籍可能包含关于try-catch-finally语句块,以及如何自定义异常和使用预定义异常类的内容。 C#.NET也支持事件和委托,这是VB6.0中没有的概念。书籍可能会...

    VB.NET 多线程 2010

    事件处理机制在多线程环境中用于通信和同步,例如,一个线程可以通过引发事件通知其他线程。 7. **异步编程模型(APM)和事件驱动编程模型(EAP)**:VB.NET支持这两种模型进行异步操作,APM主要使用Begin/End方法...

    vb.net多线程 托管例子

    托管线程是.NET框架中的一种线程模型,它由.NET运行时管理,提供了更好的内存管理和异常处理机制。 首先,我们来理解一下什么是托管代码和非托管代码。托管代码是指运行在.NET框架之上的代码,它由.NET运行时环境...

    .net 线程参考手册

    在IT领域,特别是软件开发行业中,.NET线程管理是一个至关重要的主题,它涉及多线程编程的基础理论、实践技巧以及.NET框架提供的线程管理工具和技术。本文将深入解析《.NET线程参考手册》中提及的关键知识点,帮助...

Global site tag (gtag.js) - Google Analytics