`
wangleifire
  • 浏览: 509034 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

初探C# 异常处理

    博客分类:
  • c#
阅读更多

一、基础

在C# 里,异常处理就是C# 为处理错误情况提供的一种机制。它为每种错误情况提供了定制的处理方式,并且把标识错误的代码与处理错误的代码分离开来。

对.NET类来说,一般的异常类 System.Exception 派生于 System.Object。还有许多定义好的异常类(如:System.SystemException、System.ApplicationException等),他们又派生于 System.Exception 类。其中System.ApplicationException 类是第三方定义的异常类,如果我们要自定义异常类,那么就应派生于它。

在代码中对异常进行处理,一般要使用三个代码块:

  • Try 块的代码是程序中可能出现错误的操作部分。
  • Catch 块的代码是用来处理各种错误的部分(可以有多个)。必须正确排列捕获异常的catch子句,范围小的Exception放在前面的catch。即如果Exception之间存在继承关系,就应把子类的Exception放在前面的catch子句中
  • Finally 块的代码用来清理资源或执行要在try块末尾执行的其他操作(可以省略)。且无论是否产生异常,Finally块都会执行。

二、异常处理

不管程序写得再好,异常都可能会发生,而程序也必须能够处理可能出现的错误。所以我们要站在异常一定可能会发生的角度来编写异常处理程序,应对程序有可能发生的错误建立一个良好的异常处理策略。

异 常产生的时候,我们想知道的是什么原因造成的错误以及错误的相关信息。我们可以根据实际情况抛出具体类型的异常,方便捕捉到异常时做出具体的处理。在编写 代码过程中,可以使用系统已定义的相关异常类以及自定义的异常类来实例化并抛出我们需要的异常。如一个不可能实现的接口,我们可以抛出 “System.NotSupportedExceptiion”的异常来告诉接口的调用者。

在 处理异常的时候,我们应该将可处理的具体异常分别在catch 块中做出相应处理,否则程序将终止运行。针对每一种异常,以不同方式处理,避免对所有异常做出一样的处理。并且在异常产生时,给用户一个友好的提示(普通 用户对异常的具体内容是不明白的,这就需要我们给出相关的简要信息和解决方案,或则告之联系管理员等。),并在可能的情况下给用户提供可能的选择(终止, 重试,忽略),让用户来决定程序的运行方向。同时,要将异常做日志记录。但不是所有异常都是必须记录的,比如一些可预料并且能让程序解决的错误我们就不需 要记录它。

记录异常我们可以采取如下一些方式:

  • 在文件中记录异常。便于技术人员查看所发生的异常,从而日后对程序进行改进。
  • 在数据库中记录异常。数据库支持查询,这样在后期就能够对异常进行分类查询等操作,便于查看与管理。
  • 在Eventlog中记录异常:能够远程操作,方便系统管理员监控所有计算机的异常。

除 了具体的、可预料到的异常外,还有未预料的异常。像这类异常是我们不愿意看到了,但发生了也只能暂时结束程序的运行,这里如果做好了日志就能为我们解决和 调试问题带来了方便。还有,要避免使用了try-catch但没有处理异常的情况,否则就相当于给异常放行(这种情况还不如根本就不去捕获它)。

处理完异常,我们还应该注意在finally块中释放相关资源、还原相关设置信息等收尾工作。

在做异常处理的时候,最好能在应用程序所有的入口处(事件处理函数,主函数,线程入口)使用try-catch。 但是不要在程序构造函数入口处添加try-catch,因为此处产生异常,它自己并没有能力来处理,因为它还没有构造完毕,只能再向外层抛出异常。

在 一般情况下使用异常机制来处理错误,能使整个程序的结构清晰、代码简单(标识错误的代码与处理错误代码分离),但我们也不能盲目使用异常。而且使用异常, 可能会在一定程度上影响到程序的性能(C#中使用异常一般不影响性能)。对于一些简单的、能够提前避免的错误,我们还是应该在try块外面及早做出处理。 如:

try
{
int x = y/z;
}
catch
{
// ...
}


if(z == 0)
{
Console.WriteLine("除数不能为零");
// ...
}
try
{
int x = y/z;
}
catch
{
// ...
}

附1:测试代码

Test01() 为一般嵌套异常处理

Test02() 为内层 catch 块中没有合适的处理程序存在的嵌套异常处理

Test03() 为在 catch 块中抛出异常的情况(当前处理不了该异常,那么把它再抛出)

using System;
using System.IO;

namespace ConsoleApp
{
class App
{
// 自定义异常类
public class MyException : ApplicationException
{
public MyException(string message) : base(message)
{
}

public MyException(string message,Exception innerException)
: base(message,innerException)
{
}
}

// 实例化异常对象,并抛出异常
private static void ThrowException()
{
//throw new NotImplementedException();
throw new FileNotFoundException();
//throw new IOException();
}

public static void Main()
{
Console.Write(">>> Test01" + (char)10);
Test01();

Console.Write(">>> Test02" + (char)10);
Test02();

Console.Write(">>> Test03" + (char)10);
Test03();
}

private static void Test01()
{
try
{
try
{
throw new MyException("My error.");
}
catch(MyException ex)
{
Console.WriteLine("MyException: " + ex.Message);
}
catch
{
Console.WriteLine("Unexpected error!");
}
finally
{
Console.WriteLine(" --- inside finally ---");
}

ThrowException();
}
catch(IOException ex)
{
Console.WriteLine("IOException: " + ex.Message);
}
catch(ApplicationException ex)
{
Console.WriteLine("ApplicationException: " + ex.Message);
}
catch(SystemException ex)
{
Console.WriteLine("SystemException: " + ex.Message);
}
catch
{
Console.WriteLine("Unexpected error!");
}
finally
{
Console.WriteLine(" --- outside finally ---");
}

Console.ReadLine();
}

private static void Test02()
{
try
{
try
{
// 抛出自定义异常 MyException ,
// 但内层 catch 块中没有合适的处理程序存在
throw new MyException("My error.");
}
catch(IOException ex)
{
Console.WriteLine("IOException: " + ex.Message);
}
finally
{
Console.WriteLine(" --- inside finally ---");
}
}
catch(MyException ex)
{
Console.WriteLine("MyException: " + ex.Message);
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Console.WriteLine(" --- outside finally ---");
}

Console.ReadLine();
}

private static void Test03()
{
try
{
try
{
throw new IOException();
}
catch(IOException ex)
{
// 在 catch 块中抛出异常
throw new MyException("My error." + ex.Message);
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Console.WriteLine(" --- inside finally ---");
}
}
catch(Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
finally
{
Console.WriteLine(" --- outside finally ---");
}

Console.ReadLine();
}
}
}

附2:全局异常处理、多线程中的异常处理

将 全局异常处理函数的委托加入到 Application.ThreadException 中,实现全局异常处理,但它只能处理主线程中未捕获的异常。在多线程异常处理时,工作线程/辅线程中产生异常,可以把它转给主线程来完成异常处理。如果线 程之间不通知,是无法直接捕捉异常的。若没有去处理工作线程/辅线程中产生的异常,该异常将会“消失”掉。

为 什么要把异常处理都交给主线程去做呢?举个例子:在WinForm里我们使用多线程来处理界面元素,一旦有异常发生就将异常消息显示出来。那么,是直接在 异常发生后就MessageBox,还是将消息交给MainUI来统一显示?试想一下,程序要是复杂点或是有多个界面采用多线程来显示界面元素,那么采用 前者,我们就算知道了异常的详细信息,但可能还是很难找到究竟是哪里出了问题。而通过MainUI来显示,情况就要好很多了,尤其是还设计到其他东西的时 候(如:多语言环境)。当然,这个例子只是很小的一个方面。下面就来看怎么来实现:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace ThreadApp
{
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btRun;
///
/// 必需的设计器变量。
///
private System.ComponentModel.Container components = null;

public delegate void WorkerThreadExceptionHandlerDelegate(Exception e);
void WorkerThreadExceptionHandler(Exception e)
{
this.Text = "Disposed.";
MainUIThreadExceptionHandler(this, new System.Threading.ThreadExceptionEventArgs(e));
}

public frmMain()
{
InitializeComponent();
}

///
/// 清理所有正在使用的资源。
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
///
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
///
private void InitializeComponent()
{
this.btRun = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btRun
//
this.btRun.Location = new System.Drawing.Point(72, 24);
this.btRun.Name = "btRun";
this.btRun.TabIndex = 0;
this.btRun.Text = "Run";
this.btRun.Click += new System.EventHandler(this.btRun_Click);
//
// frmMain
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(224, 69);
this.Controls.Add(this.btRun);
this.Name = "frmMain";
this.Text = "ThreadApp";
this.ResumeLayout(false);

}
#endregion

///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.ThreadException += new ThreadExceptionEventHandler(MainUIThreadExceptionHandler);
Application.Run(new frmMain());
}

public static void MainUIThreadExceptionHandler(Exception e)
{
MainUIThreadExceptionHandler(null, new System.Threading.ThreadExceptionEventArgs(e));
}

public static void MainUIThreadExceptionHandler(object sender, ThreadExceptionEventArgs t)
{
MessageBox.Show(t.Exception.Message,"Exception",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}


private void ThrowException()
{
throw new NotImplementedException();
}

private void Run()
{
try
{
this.Text = "Waiting..."; //[错误]这里在2.0里是编译不通过的。因为它已经违背了我们的原则——不要跨线程操作(当前线程对界面线程的元素进行了操所)
Thread.Sleep(2000);
this.Text = "Throw Exception...";
ThrowException();
this.Text = "Finished"; //[错误](同上)
}
catch(Exception e)
{

// 如果涉及到多线程的互操作时,
// 可以运用BeginInvoke方法来实现多线程间的互访问。
this.BeginInvoke(
new WorkerThreadExceptionHandlerDelegate(
WorkerThreadExceptionHandler),
new object[]{e}); }
}

private void btRun_Click(object sender, System.EventArgs e)
{
ThreadStart ts = new ThreadStart(Run);
Thread t = new Thread(ts);
t.Start();

//throw new NotSupportedException();
}
}
}

分享到:
评论

相关推荐

    C# 入门初探.

    C# 是一种面向对象的编程语言,由微软公司开发,主要用于构建Windows应用程序、Web应用程序以及游戏等。...随着对C#的深入学习,你将掌握更多高级特性和编程技巧,例如面向对象编程、异常处理、集合、多线程等。

    C#网络编程初探[参照].pdf

    值得注意的是,实际应用中,通常需要添加异常处理和数据处理逻辑,以及适当的关闭连接和资源释放。 C/S(客户端/服务器)结构的软件通常采用异步非阻塞模式,这样服务器可以同时处理多个客户端的连接请求,提高服务...

    C#超酷教程

    4. **异常处理**:“解决SP2验证码问题.reg”可能涉及到错误处理和异常处理,学习如何使用try-catch块来捕获和处理运行时可能出现的问题。 5. **文件操作**:虽然文件名没有直接表明文件操作,但C#教程通常会包含这...

    C#开发实战宝典.(清华出版.王小科等).part1

     全书共分30章,主要内容包括初探C#及其开发环境,认识C#代码结构,C#程序设计基础,选择结构控制,循环结构控制,字符及字符串,数组、集合与哈希表,面向对象程序设计,Windows窗体设计,Windows应用程序常用控件...

    C#开发实战宝典.(清华出版.王小科等).part2

     全书共分30章,主要内容包括初探C#及其开发环境,认识C#代码结构,C#程序设计基础,选择结构控制,循环结构控制,字符及字符串,数组、集合与哈希表,面向对象程序设计,Windows窗体设计,Windows应用程序常用控件...

    c#开发实战宝典 明日科技 源代码

    全书共分30章,主要内容包括初探C#及其开发环境,认识C#代码结构,C#程序设计基础,选择结构控制,循环结构控制,字符及字符串,数组、集合与哈希表,面向对象程序设计,Windows窗体设计,Windows应用程序常用控件,...

    c#写的后台管理程序

    6. **异常处理**:良好的错误处理机制能提高程序的稳定性和用户体验。C#的try-catch-finally结构用于捕获和处理异常,确保程序在遇到错误时能够优雅地恢复或终止。 7. **多线程**:对于处理大量并发请求的后台程序...

    C#文本文档编辑器

    C#支持类、接口、继承、多态等面向对象特性,还引入了自动垃圾回收、异常处理和类型安全等现代编程概念。在我们的文本文档编辑器项目中,这些基础知识将构成程序的基石。 二、文本编辑器的基本功能 1. 文件操作:...

    C#语言编写初期简单版的俄罗斯方块

    对于可能出现的异常情况,如非法输入或资源不足,应设置适当的异常处理代码。 通过这个简单的俄罗斯方块项目,初学者不仅可以掌握C#的基本语法和面向对象编程的概念,还能深入了解游戏开发的流程和技巧。随着对C#的...

    C#委托与事件初探

    2. 在适当的时候使用`null`检查,避免空引用异常。 3. 使用`EventArgs`类或其子类传递事件数据。 4. 使用`protected virtual`方法(如`OnSomeEvent`)来允许派生类重写事件处理逻辑。 ### 六、委托和事件在实际应用...

    c#做的一个QQ程序,还有不足的地方...适合菜鸟下载下去消化,老鸟不要笑

    C#提供了try-catch语句来捕获和处理异常,而日志记录则可以帮助开发者追踪和诊断问题。在"MyQQ"程序中,可能有相应的错误处理机制和日志系统,以确保程序的稳定运行。 总的来说,"MyQQ"项目是一个综合运用C#语言和...

    C#之CLR内存原理初探

    CLR作为.NET框架的核心组成部分,负责管理代码的执行,包括内存管理、类型安全、异常处理等多个方面。本文主要探讨的是CLR内存原理,特别是与C#程序执行密切相关的托管堆、栈以及字符串常量池。 首先,我们要了解C#...

    学生信息管理系统.rar

    《学生信息管理系统——初探C#与Visual Studio 2005编程实践》 学生信息管理系统是一款基于C#编程语言,利用Visual Studio 2005开发环境构建的初级应用软件。这款系统针对初学者设计,尽管功能相对简单,但它为理解...

    asp程序asp程序有关asp的程序

    在压缩包的文件名称列表中,我们看到一系列以"腾讯社区:初探c#"为主题的网页文件。这些文件很可能是一个关于C#编程的学习资源,由腾讯社区的用户分享,旨在帮助初学者理解C#的基础知识和核心概念。文件名中的数字...

    asp.NetC#教程

    7. **异常处理**:学习如何捕获和处理运行时错误,以及创建自定义异常。 8. **部署和发布**:理解如何将ASP.NET应用程序部署到IIS服务器,进行测试和生产环境的配置。 9. **AJAX技术**:了解如何使用ASP.NET AJAX...

    基于Asp.Net的管理信息系统初探

    它支持泛型、异常处理、垃圾回收等现代编程特性,提高了代码的可读性和可维护性。 2.3 SQL Server数据库 SQL Server是微软公司的关系型数据库管理系统,它提供了强大的数据存储和查询能力。在Asp.Net应用中,SQL ...

    小金库记账系统源码(适合初学者使用)

    首先,C#是一种由微软公司推出的面向对象的编程语言,它在设计时就考虑了现代软件开发的需求,如类型安全、垃圾回收、异常处理等。在这款记账系统中,C#的特性得到了充分展示,比如类和对象的概念,以及事件驱动编程...

    WindowsFormsLamp.rar

    《Windows Forms Lamp:C# WinForms编程初探》 Windows Forms(简称WinForms)是.NET框架下用于构建桌面应用程序的库,它为开发者提供了一种简单直观的方式来创建交互式的用户界面。在“WindowsFormsLamp.rar”这个...

Global site tag (gtag.js) - Google Analytics