公共语言运行库提供一种异常处理模型,该模型基于对象形式的异常表示形式,并且将程序代码和异常处理代码分到 try 块和 catch 块中。可以有一个或多个 catch 块,每个块都设计为处理一种特定类型的异常,或者将一个块设计为捕捉比其他块更具体的异常。
如果应用程序将处理在执行应用程序代码块期间发生的异常,则代码必须放置在 try 语句中。try 语句中的应用程序代码是 try 块。处理由 try 块引发的异常的应用程序代码放在 catch 语句中,称为 catch 块。零个或多个 catch 块与一个 try 块相关联,每个 catch 块均包含一个确定该块处理的异常类型的类型筛选器。
在 try 块中出现异常时,系统按所关联 catch 块在应用程序代码中出现的顺序搜索它们,直到定位到处理该异常的 catch 块为止。如果某 Catch 块的类型筛选器指定 T 或任何派生出 T 的类型,则该 catch 块处理 T 类型的异常。系统在找到第一个处理该异常的 catch 块后即停止搜索。因此,正如本节后面的示例所演示的那样,在应用程序代码中处理某类型的 catch 块必须在处理其基类型的 catch 块之前指定。处理 System.Exception 的 Catch 块最后指定。
如果当前 try 块所关联的所有 catch 块均不处理该异常,且当前 try 块嵌套在当前调用的其他 try 块中,则搜索与下一个封闭 try 块相关联的 catch 块。如果没有找到用于该异常的 catch 块,则系统搜索当前调用中前面的嵌套级别。如果在当前调用中没有找到用于该异常的 catch 块,则将该异常沿调用堆栈向上传递,搜索上一个堆栈帧来查找处理该异常的 catch 块。继续搜索调用堆栈,直到该异常得到处理或调用堆栈中没有更多的帧为止。如果到达调用堆栈顶部却没有找到处理该异常的 catch 块,则由默认的异常处理程序处理该异常,然后应用程序终止。
接下来我们看一个实例,为了每一次的实例都能够多学到一点知识,下例在完成针对使用try/catch处理异常的演示之外,还将实例程序稍微复杂了下。
1. 创建一个名为“异常第一个实例”的Windows桌面应用程序;
2. 修改Form1的Text属性为“超级简单计数器”,在Form1上分别放置如下控件:
i. 两个TextBox,分别修改name属性为tb_number1和tb_number2;
ii. 在两个TextBox中间放一个ComboBox,并修改name属性为cb_flag,点击该控件上的小三角形,选择“编辑项”,插入“+、-、*、/”四个符号,注意每个符号都要用回车键换行。最后修改该控件的Text属性为“+”;
iii. 放一个Button控件,并修改Text属性为“计算”;
iv. 放一个Label,修改Text属性为“计算结果 : ”,再放一个Label,修改name属性为lbl_result;
3. 双击“计算”按钮,在button_click事件中输入如下代码:
private void button1_Click(object sender, EventArgs e) { try { //从tb_number1和tb_number2中获取要计算的字符 //建议你自己用if语句判断下用户是否向这两个文本框输入了值 string txt1 = tb_number1.Text; string txt2 = tb_number2.Text; //将字符串转换为int类型 int num1 = int.Parse(txt1); int num2 = int.Parse(txt2); //计算,在计算的时候我们使用switch来判断用户是选择的哪一个运算符 int result; //该变量用来记录运算结果 switch (cb_flag.Text) { case "+": result = num1 + num2; break; case "-": result = num1 - num2; break; case "*": result = num1 * num2; break; case "/": result = num1 / num2; break; default: result = 0; break; } lbl_result.Text = result.ToString(); } catch { MessageBox.Show("对不起,你的输入有误,请重新输入!"); //弹出提示 return; //这一句是让程序返回起点 } } |
4.大功告成,来运行程序看看我们做的第一个计算器吧。故意输入错误
5.来,我们在button_click事件的前面的大括号这一行打一个断点,然后运行,当点击计算可以看到,当运行到由字符串转换为INT类型这一行的时候,编译器捕获到异常,就直接跳到catch这一块代码上了,换句话说,catch这一块代码就是用来处理异常的。如果我们输入正确的数字,则能够顺利把try语句块中的代码全部都运行完。然后根本不会去运行catch块的代码。
老田:从上面看得出来,我们将可能出现错误的代码放在try语句块中。而将处理这些可能出现的错误的代码则放在catch语句块中。
小天:为什么用return?在try后面是否可以不用catch或者用多个catch呢?
老田:如果catch块中没有退出的代码(如return,throw),catch块后的代码将继续得到执行。并且try 块后面至少需要包含一个 catch 块,或一个finally块(稍后讨论)。