目录
什么是异常
异常是在运行期间代码中产生的错误。
int[] myArray = {1,2,3,4}; int myEle = myArray[4];//数组下标越界
运行到这里的时候,会出现异常,这个异常的定义已经在CLR中定义好了。如果我们不去处理这个异常,那么当异常发生的时候,程序会终止掉,然后异常后面的代码都无法执行。
try 语句
try 语句允许您指定要保护的代码块以防止出现异常,并在异常发生时提供处理异常的代码。
其中 catch 块可以有0或者多个,这里是处理异常的代码段,也被称为异常处理程序。
finally 可以有0或者1个。无论 try 块中是否抛出异常,此块都包含要执行的代码,即此块只要有,无论有没有发生异常,都会被执行。
namespace HelloWorld_Console
{
class Program
{
static void Main(string[] args)
{
int x = 10;
try
{
int y = 0;
x /= y; // Raises an exception
}
catch // 如果 catch 块没有参数表,表示该块无论出现什么异常,都会被执行
{
WriteLine("Handling all exceptions - Keep on Running");
}
ReadKey();
}
}
}
System.Exceptin 异常类 (461P)
程序中可能会出现许多不同类型的异常。BCL定义了许多异常类,每个异常类代表一种特定的异常类型。 当其中一个发生时,CLR会执行以下操作:
- 它为该类型创建异常对象。
- 它寻找一个合适的 catch 子句来处理它。
所有异常类都派生自 System.Exceptin类, 下图显示了异常继承层次结构的一部分:
异常对象包含只读属性,其中包含导致异常的信息。下图显示了其中一些属性:
catch 子句
catch 子句处理异常的形式有3种, 允许处理不同类型的异常。 如图所示:
- 如图所示的第一种 catch子句能接受任何异常, 但不能确定导致它的异常类型。这只允许对任何可能发生的异常进行普通处理和清理。
- 特定catch子句形式把一个异常类的名称作为参数。它匹配指定类的异常或从中派生的异常类的异常。
- 带有对象的特定catch子句提供了关于异常的最多信息。它匹配指定类的异常或从中派生的异常类的异常。它通过将异常对象分配给异常变量,为您提供对CLR创建的异常对象的引用。您可以在catch子句的块中访问异常变量的属性,以获得关于引发的异常的特定信息。
namespace HelloWorld_Console { class Program { static void Main(string[] args) { try { int[] myArray = { 1, 2, 3, 4 }; int myEle = myArray[4];//数组下标越界 } catch(IndexOutOfRangeException e) { Console.WriteLine("Message: {0}", e.Message); //输出发出异常的原因 Console.WriteLine("Source: {0}", e.Source); // 输出发出哪个程序集发生了异常 Console.WriteLine("Stack: {0}", e.StackTrace); // 这个程序集发出异常的具体位置 } } } }
如果你的 catch 子句接受一个参数, ,那么系统会把这个异常变量设置为异常对象, 这样你就可以检查并确定异常的原因。如果异常是前一个异常引起的, 你可以通过异常对象的 InnerException属性 来获得对前一个异常对象的引用。
catch 子句部分可以包含多个catch子句,如图所示:
当异常发生时,系统按顺序搜索 catch 子句列表,并执行与异常对象类型匹配的第一个catch子句。因此,在对catch子句进行排序时,有两条重要的规则。它们如下:
- 特定的catch子句必须先按最特定的异常类型排序,然后按最一般的顺序排序。
- 如果有一个 一般 catch 子句,它必须是最后一个, 并且在所有特定catch子句之后。不鼓励使用一般catch子句, 因为它允许程序继续执行隐藏错误,让程序处于一种未知的状态。应尽可能使用特定catch子句。
finally 块 (464P)
- 如果一个 try 语句带有 finally 块,那么 无论try 语句不不会发生异常, finally 语句都会被执行。
- 注意: 如果只有 try 和 finally 块, 那么当在 try 中发生异常时, finally 块中的语句还是会执行, 但是在 finally 块之后的语句就不会被执行了。 最后的结果还是会抛出异常信息的。
- 如果 当try 块中发生的异常, 如果有多个非一般的 catch 块,但是发生的异常类型并没有匹配到其中的任何一个, 那么(如果有的话)finally 就会被执行,但是在 finally 块之后的语句就不会被执行了。 最后的结果还是会抛出异常信息的。
- 即使 try 块有一个 return 语句或者在 catch块中抛出了异常,finally块也将始终在返回调用代码之前执行。
namespace HelloWorld_Console
{
class Program
{
static void Main(string[] args)
{
int inVal = 5;
try
{
if (inVal < 10)
{
Console.Write("First Branch - "); // 先执行这一语句
return;
}
else
Console.Write("Second Branch - ");
}
finally
{ Console.WriteLine("In finally statement"); } // 再执行这一语句
}
}
}
使用 throw 语句 抛出一个异常 (469P)
可以使用 throw 语句显式地抛出一个异常,语法为:
throw ExceptionObject;
namespace HelloWorld_Console
{
class MyClass
{
public static void PrintArg(string arg)
{
try
{
if (arg == null)
{
ArgumentNullException myEx = new ArgumentNullException("arg");
throw myEx;
}
Console.WriteLine(arg);
}
catch (ArgumentNullException e)
{
Console.WriteLine("Message: {0}", e.Message);
}
}
}
class Program
{
static void Main()
{
string s = null;
MyClass.PrintArg(s);
MyClass.PrintArg("Hi there!");
}
}
}
输出结果为:
Message: Value cannot be null.
Parameter name: arg
Hi there!