C#入门经典-- 7.2 错误处理
(一)异常
异常是代码中产生的错误,或者在运行期间由代码调用的函数产生的错误。例如,如果函数的一个字符串参数不是以a开头,就产生一个异常。这并不是严格意义上的函数外部错误,但调用该函数的代码把它看作函数外部错误。
1、try...catch...finally
C#语言包含结构化异常处理(Structured Execption Handing,SEH)的语法。关键字可以标记出能处理异常的代码和指令,如果发生异常,就使用这些指令处理异常。用于这个目的的三个关键字是try,catch和fianlly。它们都有一个关联的代码块,必须在连续的代码行中使用。其基本结构如下:
try
{
...
}
catch(<exceptionType> e)
{
...
}
finally
{
...
}
也可以只有try块和finally块,而没有catch块,或者有一个try块和好几个catch块。如果有一个或多个catch块,finally块是可选的,否则就是必需的。
这些代码块的用法如下:
- try --包含产生异常的代码。
- catch -- 包含产生异常时要执行的代码。catch块可以使用<exceptionType>,设置为只响应特定的异常类型,以便提供多个catch块。还可以完全省略这个参数,让一般的catch块响应所有的异常。
- finally -- 包含总是会执行的代码,如果没有产生异常,则在try块之后执行,如果处理了异常,就在catch块后执行,或者在未处理的异常中断应用程序之前执行(此时处理这个块,其原因是存在这个块,否则也可以在这个块的后面放置代码)。
在try的代码中出现异常后,发生的事件依次是:
- try块在发生异常的地方中断程序的运行。
- 如果有catch块,就检查该块是否匹配于已发生的异常类型。如果没有catch块,就执行finall块(如果有catch块,就一定要执行finally块)。
- 如果有catch块,但它与已发生的异常类型不匹配,就检查是否有其他catch块。
- 如果有catch块匹配于已发生的异常类型,就执行它包含的代码,再执行finally块(如果有)。
- 如果catch块不匹配于已发生的异常类型,就执行finally块(如果有)。
【示例】
class Program
{
static string[] eTypes = {"none","simple","index","nest index"};
static void Main(string[] args)
{
foreach(string eType in eTypes)
{
try
{
Console.WriteLine("Main() try block reached.");
Console.WriteLine("ThrowException(\"{0}\") called.",eType);
ThrowExecption(eType);
Console.WriteLine("Main() try block continues.");
}
catch(System.IndexOutOfRangeException e)
{
Console.WriteLine("Main() System.IndexOutOfRangeException catch"
+ " block reached. Message:\n\"{0}\"",e.Message);
}
catch
{
Console.WriteLine("Main() general catch block reached.");
}
finally
{
Console.WriteLine("Main() finally block reached.");
}
Console.WriteLine();
}
Console.ReadKey();
}
static void ThrowExecption(string execptionType)
{
Console.WriteLine("ThrowExecption(\"{0}\") reached.",execptionType);
switch(execptionType)
{
case "none":
Console.WriteLine("Not throw an exception.");
break;
case "index":
Console.WriteLine("Throwing System.IndexOutOfRangeException.");
eTypes[4] = "error";
break;
case "nested index":
try
{
Console.WriteLine("ThrowException(\"nested index\") " +
"try block reached.");
Console.WriteLine("ThrowException(\"index\") called");
ThrowExecption("index");
}
catch
{
Console.WriteLine("ThrowException(\"nested index\") general"
+ " catch block reached.");
}
finally
{
Console.WriteLine("ThrowException(\"nested index\") finally"
+ " block reached.");
}
break;
case "simple":
Console.WriteLine("Throwing System.Exception.");
throw new System.Exception();
// break;
}
}
}
2、列出和配置异常
VS提供了一个对话框,可以检查和编辑可用的异常,该对话框可以使用调试|异常...菜单选项(或者按下Ctrl+D,E)打开。异常按照类别和.NET库命名空间列出。扩展Common Language Runtime Execption选项,再扩展System选项,就可以看到System命名空间中的异常。
每个异常都可以使用右边的复选框来配置。可以使用第一个选项“引发”中断调试器,即使是对于要处理的异常,也是这样。 第二个选项可以忽略未处理的异常,这样做会对结果有影响。在大多数情况下,这会进入中断模式,所有只需在异常环境下这么做。
3、异常处理的注意事项
注意,必须在更一般的异常捕获之前为比较特殊的异常提供catch块。如果catch块的顺序错误,应用程序就会编译错误。
还要注意可以在catch块中产生异常,方法是使用上一个示例中方式,或使用下述表达式:
throw;
这个表达式会再次产生catch块处理过的异常。如果以这种方式产生异常,该异常就不会由当前的try...catch...finally块处理,而是由上一级的代码处理(但嵌套结果中的finally块仍会执行)。