以下是我节选自我的新书(还正在写,嘎嘎)中的一小段。我觉得最后一段对初学者特有用。
如果你是个初学者的话,我建议你看看,练练。
==================================================================================
接下来我们看一个实例,为了每一次的实例都能够多学到一点知识,下例在完成针对使用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-4
图3-4
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. 大功告成,来运行程序看看我们做的第一个计算器吧。故意输入错误,看到效果如图3-5
图3-5
5. 来,我们在button_click事件的前面的大括号这一行打一个断点,然后运行,当点击计算可以看到,当运行到由字符串转换为INT类型这一行的时候,编译器捕获到异常,就直接跳到catch这一块代码上了,换句话说,catch这一块代码就是用来处理异常的。如果我们输入正确的数字,则能够顺利把try语句块中的代码全部都运行完。然后根本不会去运行catch块的代码。
小天:为什么用return?在try后面是否可以不用catch或者用多个catch呢?
老田:如果catch块中没有退出的代码(如return,throw),catch块后的代码将继续得到执行。并且try 块后面至少需要包含一个 catch 块,或一个finally块(稍后讨论)。
小天:我觉得上面的实例还是不完美,因为在运行中出现错误的时候,我们只能获得一个我们自定义的警告信息,还有没有更好的解决方案呢?
老田:当然有,那就是为每个可能的Exception定制解决方法。例如,上面的实例将有可能出现不同的Exception,我们则可以将Exception进行细分:类型有错误(FormatException)、超过数值范围(OverflowException)、无效输入(Exception ex),然后根据不同的Exception提出不同的解决方法。下面我们来对上面的实例进行完善。
if (tb_number1.Text != "" && tb_number2.Text != "") {//在处理前线判断用户是否输入了值。 //节约系统开支(想下什么这里说这样做是为了节约系统开支) try { //从tb_number1和tb_number2中获取要计算的字符 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 (FormatException fex) { //MessageBox.Show(fex.Message); //直接弹出异常所携带的消息 //弹出的警告框会让人厌恶所以我们可以使用下面的代码来改善用户体验 lbl_result.Text = fex.Message; //让显示结果的label来显示提示。 lbl_result.ForeColor = Color.Red;//为了更显眼,让字体变为红色 //这里留一个作业,就是让字体变大,自己查MSDN return; } catch (OverflowException ofex) {//溢出错误 MessageBox.Show(ofex.Message); //直接弹出当前捕获的异常所携带的消息 return; } catch (DivideByZeroException dze) {//除零 MessageBox.Show(dze.Message); //直接弹出当前捕获的异常所携带的消息 return; } catch (Exception ex) {//无效输入 MessageBox.Show(ex.Message); //直接弹出当前捕获的异常所携带的消息 return; } } else {//如果没有输入完整的值,这里给出提示 MessageBox.Show("请先输入有效的值"); return; } |
上面的实例中,我们留下了几个可以给你自己修改实例达到举一反三的地方:
1. 单独判断两个文本框是否输入了合适的值,并给出不同的提示;
2. 改变if语句所在的位置,实现同样的效果;
3. 改变提示错误信息的方式;
4. 尝试删除return,看下异常和else语句块中的有什么区别;
5. 自己查询MSDN,尝试再增加一个catch语句块;
6. 自己在代码中动态修改Label的更多属性;
上述练习的意义一点都不低于这个例题本身。我也只是在这个例题中为大家提出一种举一反三的思路。希望一直以为举一反三只是一种传说的朋友时刻以此反省。
另外上面例题中还有一点是每一位初学者应该去深入理解的。就是在本例中几乎将前面学过的知识都尽量的融合进去了。
当我们遇到新的知识的时候一定要想法设法把已经学过的知识融入到新的知识里面,哪怕现在看起来那绝对是多此一举。在长期的教学实践中,我发现大部分的学生都有一个通病,那就是根本无法将所有学过的知识融合起来使用。
学技术的人分为三等:
1. 能够使用已经学到的技术;
2. 能够灵活运用所学的知识,并且在多套方案中找到最优化的知识点组合来实现一个优秀的解决方案;
3. 能够灵活运用所学的知识,并且在解决方案中融入自己的思想。
小天:我觉得最后一种人不是初学者能够做到的。而且我觉得第二种就很不错了。
老田:你错了。第二种人只能算一个优秀的技术工人。但绝对不会是一个顶尖的技术牛人。而要做到把自己的思想融入解决方案也并非只对大型项目才有效。说个很简单的示例。比如军棋推演,在退一步,比如搭积木。从这些非常小的项目(我们将一切都当成项目来看待)中都可以看到思想的光芒。不同的是,平庸的人展示的是别人的思想。而顶尖的人展示的是自己的思想。
小天:问题是我们现在学习的这些知识连编程都算不上,怎么会有思想?
老田:真的没有吗?我们上例中提到的提高用户体验,提高系统性能。这些不是吗?其实思想无所谓大小,只是看你是否在用心去做每一个实例而已。
另外,如果你看完这段观点后,认为你是第一种人。并且无法成为第三种人甚至第二种人。那么我建议你赶紧放下这本书。同时我要毫不留情的送你一句话:“如果你对任何事都无法用心,那么你可以停止浪费粮食和浪费所有关心你的人的感情了”。