当前位置:编程学习 > C#/ASP.NET >>

.NET中的Exception处理(C#)

答案:     摘要:
  本文以C#为编程语言,讨论了 .NET 中的异常处理方式,主要包括 try/catch 块、finally语句、Exception 对象、throw语句等主题。
  --------------------------------------------------------------------------------
  
  本文内容
  理解异常的基本概念
  使用 try/catch 块处理异常
  理解finally的意义
  使用 Exception 对象确定异常
  将异常返回过程调用程序
  
  --------------------------------------------------------------------------------
  
  基本概念
  就像其他面向对象语言一样,C#采用异常(exception)来应对程序错误和非正常情况。
  
  异常是包含程序非正常事件信息的对象。与缺陷(bug)不同,一个bug是程序员的疏漏,它们应该在产品发布前被更正;尽管一个bug可能引发异常的抛出,你不应该完全依靠异常来处理你的bug,它至多是你测试的手段,你应该自己更正哪些bug。类似的,错误(error)是由用户操作而引起,比如在一个应该输入字母的地方用户输入了一个数字;虽然它也可能引发异常,但你应该通过校验代码(validation code)来抓住这些错误。无论何时,在可能的情况下错误都应该是能预料和能被预防的。即使你除去了所有的bug和列举了所有可能的用户错误,你仍会遇到无法预料和阻止的异常,如内存耗尽、网络崩溃。你无法预防异常,但你能处理它们,以避免它们使你的程序崩溃。
  
  当你的程序遇到一个非正常情况,比如说内存不足,它就会引发(throw/raise)一个异常。此时,当前的过程调用将挂起,.NET 运行时(CLR)将从下至上搜索过程调用堆栈,以查找相应的异常处理程序。也就是说,如果抛出异常的代码正处于某个 Try 块中,运行时将首先使用本地的 Catch 块(如果有)来处理异常(它将执行在该位置找到的 Catch 块代码),否则这个程序段将被终止并将异常的处理权交给其调用函数;如果没有函数处理此异常(即在整个调用堆栈中没能找到适当的 Catch 块),最终运行时将会得到并处理它,并立刻将你的程序终止。
  
  
  --------------------------------------------------------------------------------
  
  引发错误
  示例为一个简单的文件打开操作并检索其长度的程序(以后几个示例的内容基本相同),示例从窗体文本框textBoxfilepath中得到文件名:
  
  string filepath=this.textBoxfilepath.Text;
  long isize;
  FileStream fs=File.Open(filepath,FileMode.Open);
  isize=fs.Length;
  fs.Close();
  
  有许多原因会使代码引发异常,如文件不存在,访问权限不够等等。在现在这种没有异常处理的情况下,运行时发生的任何错误会回溯到.NET运行时(CLR);而运行时会呈现给用户一个让人费解并可能造成危险的对话框(图1)。为了避免出现此对话框,如果发生运行时错误,您至少需要向顶层过程添加异常处理,并在必要时在下层过程中也添加异常处理。
  
  
  图1:包含的Continue按钮使 .NET 默认错误处理程序变得有些危险。
  
  此外,其中的详细信息并不是您希望用户看到的内容。
  
  
  --------------------------------------------------------------------------------
  
  添加简单try/catch块处理异常
  在C#中,为了恰当地处理运行时异常,在要需要保护的任何代码附近添加一个 try/catch块。在 try 块的代码中发生的任何运行时异常都将立即使用 catch 块中的代码继续执行:
  
  try
  {
  string filepath=this.textBoxfilepath.Text;
  long isize;
  FileStream fs=File.Open(filepath,FileMode.Open);
  isize=fs.Length;
  fs.Close();
  }
  catch
  {
  MessageBox.Show("error occured!");
  }
  
  这段代码运行时,当有异常出现(如文件不存在)程序不会显示图2的对话框,取而代之的是一条简单的"error occurred!"警告,因为try块捕获住了异常并立即转到catch块中的代码继续执行。
  
  注意:如果catch块中没有退出的代码(如return,throw),catch块后的代码将继续得到执行。并且try 块后面至少需要包含一个 catch 块(有关包含多个 catch 块的详细信息,请参阅下文)或一个finally块(参阅下文)。
  
  
  --------------------------------------------------------------------------------
  
  处理特定异常(多个catch块)
  .NET 框架提供了大量的特定异常类,所有这些异常类都是从基类 Exception 类继承而来的。在 .NET 框架文档中,您会看到一些表,它们列出了在调用任何方法时都可能出现的所有异常。图 2便列出了.NET中File.Open()方法调用时可能发生的所有异常情况:
  
  
  图 2: File.Open 可能发生的所有异常
  
  你可以在一个try块后添加足够多的 Catch 块,以便对不同的异常情况作出不同的处理。以下的代码就列举了对几个不同的异常进行不同处理的情况。
  
  try
  {
  string filepath=this.textBoxfilepath.Text;
  long isize;
  FileStream fs=File.Open(filepath,FileMode.Open);
  isize=fs.Length;
  fs.Close();
  }
  catch(UnauthorizedAccessException uex)
  {
  MessageBox.Show(uex.Message);
  }
  catch(FileNotFoundException fex)
  {
  MessageBox.Show(fex.Message);
  }
  catch(NotSupportedException nex)
  {
  MessageBox.Show(nex.Message);
  }
  catch(ArgumentException aex)
  {
  MessageBox.Show(aex.Message);
  }
  catch
  {
  MessageBox.Show("error occured!");
  }
  
  注意:catch块的次序必须十分小心,比如一个DivideByZeroException 异常继承自ArithmeticException异常,如果你先捕获后者,则当除数为0时抛出的异常就会进入ArithmeticException块而永远不会进入DivideByZeroException块。事实上,当这种情况出现时,编译器会发现DivideByZeroException块不能被执行到,并会报告一个编译错误。
  
  
  --------------------------------------------------------------------------------
  
  Finally关键字
  除了 try 和 catch 块中的代码外,有时你还需要添加无论何种情况下都会被执行到的代码,比如你可能需要释放一些资源、关闭一个文件等等,这是就需要使用Finally 关键字在 Catch 块后添加 Finally 块。即使代码抛出异常,并在Catch 块中添加了显式的return语句,finally块中的代码仍会被执行。Finally 块中的代码将在异常处理代码之后、控制返回到调用过程之前执行。
  
  注意:finally 块只需要一个 try 块,catch 块的存在与否对其并没有影响。使用break,continue,return语句退出 finally 块都是非法的。
  
  我们对上面的示例进行如下修改,以使任何情况下都可以调用结束代码,关闭可能打开了的文件:
  
  FileStream fs=null;
  try
  {
  string filepath=this.textBoxfilepath.Text;
  long isize;
  fs=File.Open(filepath,FileMode.Open);
  isize=fs.Length;
  }
  catch(FileNotFoundException fex)
  {
  MessageBox.Show(fex.Message);
  }
  catch
  {
  MessageBox.Show("error occured!");
  }
  finally
  {
  //无论发生什么情况,下面的代码都将被执行到
  if(null!=fs)
  {
  fs.Close();
  }
  }
  
  
  --------------------------------------------------------------------------------
  
  Throw 关键字
  在C#中,要通知一个非正常情况,你可以使用 throw 关键字抛出一个异常。下面一行代码创建一个新的System.Exception实例,并将它抛出:
  
 

上一个:C# 事件及响应方法
下一个:对.NET Framework 事件机制理解的代码分析

CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,