异常即法式运行时发作的错误(错误其实不老是编程人员的原因,有时应用法式也会因为用户或运行代码的情况改动而发作错误;越大的法式越容易发作异常

异常处置(exceptional handling)机造别离了领受和处置错误代码,功用用于理清编程者的思路,加强了代码可读性,便利了后期维护者的阅读和理解

异常处置(或错误处置)供给了处置法式运行时呈现的任何不测或异常情况的办法,异常处置中利用 try,catch与finally三个关键字来测验考试处置捕捉的异常(不成能捕捉所有的异常)

1)发现错误(利用try包裹可能会呈现的异常代码,一般叫做异常捕捉) 2)处置错误(在catch语句块处置捕捉异常) 3)不管异常在2)中能否处置城市施行

留意事项:

1)发作异常后,在try语句块中异常代码之后的代码不再施行

2)finally块中的代码,无论能否发作异常城市施行;也不克不及写return语句(报错)

3)即便try语句块中有return语句,finally语句块也会施行

4)若是所有的异常都不婚配catch,最初仍然施行finally语句块中的代码(若是有)

语法错误类的异常

那个异常绝大大都VS东西会帮我们识别出来,根本无法生成法式集;处置办法:按照错误列表的提醒逐个矫正语法错误的代码

static void Main(string[] args){//应该与行号12 构成闭合的语句块 //1 语法错误 //类型应该是 小写 int Int num = 6; //int i=0后面应该是分号 for (int i = 0,i < 6; i++) { Console.WriteLine(i); } Console.ReadKey(); //}//不小心正文掉招致Main()办法的语句块无法闭合 //那类错误太多无法穷举,VS会有提醒C# - 异常处理 087  第1张

语法错误的异常

处置时先按行号最小,行号不异的按列号停止处置(前面的错误会招致后面呈现许多"无效"的联系关系错误)如上图只因一个分号隐藏了Int,联系关系了除X1外六个错误信息

逻辑错误错误类的异常

那个异常编译没问题,施行不报异常,就是成果不合错误;处置办法:能够通过调试监视变量

static void Main(string[] args){ //逻辑错误 //如原来是计算两个数的和 int n = 3; int m = 2; //不小心书将 + 写为 - int sum = n - m;//成果 1 Console.WriteLine("n + m = {0}", sum); //简化的逻辑错误代码示例 //若是呈现在复杂的来回挪用的办法中... //更好通过调试监视颠末每个办法后变量的值 Console.ReadKey();}

以上两品种型的异常根本用不到异常处置机造

招致法式瓦解的异常

能够通过编译,只是在法式运行期间呈现错误,招致法式瓦解;那个需要利用异常处置机造,利用它能够使法式跳过那个异常代码,继续施行那个异常之后的代码(已捕捉了异常)

现今能够碰到的如:

1)两个操做数相除或取余时的异常;测验考试除以零

2)利用如利用Convert,Parse,TryParse等停止类型转换;输入字符串的格局不准确

3)利用引用类型对象时;未将对象引用设置到对象的实例

4)其他的如操做文件或数据库时等因文件没了或没有操做权限等

static void Main(string[] args){ //编译胜利,运行抛异常 //1 测验考试除以零 int n = 8; int m = 0; int s = n / m; //抛异常 //2 输入字符串的格局不准确 string num = "ooo";//字母o Convert.ToInt32(num); int.Parse("ooo"); int.TryParse(num, out n); //引用类型容易呈现的异常 //3 未将对象引用设置到对象的实例 //专有名词: 空指针异常 string str = null; str.ToString(); Console.ReadKey();}C# - 异常处理 087  第2张

代码抛出异常

法式抛出异常招致法式瓦解,无法继续施行,会给用户带来十分欠好的利用体验(什么垃圾破软件....)

捕捉异常并处置

异常处置的一般应用形式(三者同用体例):

try{捕捉有可能呈现异常的代码}当碰到异常时,try语句块中后续代码不再施行。

catch{处置捕捉的异常}一般操做如记录日记,向上抛出等操做(只要发作了异常才会施行)

catch语句块中有时利用throw关键字将捕捉的异常抛给"上级"去向理

finally{无论能否发作或捕捉异常城市施行的代码}一般用于释放内存或资本等操做

其他的应用体例:

体例1) try → 多个catch → 一个finally

体例2) try→(1个或多个catch)多个catch的挨次问题,没有finally。

体例3) try→finally(只能有一个)没有catch

static void Main(string[] args) { Console.WriteLine("1 法式起头施行"); //那个赋值在此没有任何错误 string num = "ooo"; try { //有可能发作异常的代码 int s = 0; Console.WriteLine("2 抛出异常之前 s = {0}", s); //当法式施行到异常代码后会间接跳转到catch语句块中 s = int.Parse(num);//有可能抛出异常 Console.WriteLine("3 抛出异常之后 s = {0}", s); //除了行号11,其余根本都是"无效"代码 //两个输出语句次要是显示有异常时 //在异常代码前后的代码施行情况 } catch (Exception) //Exception处置异常的类 { //只要try中有异常时才会进入此语句块 //若是try中没有异常,间接跳转到finally语句块中 Console.WriteLine("4 法式发作异常了!!!"); //施行完后跳转到finally语句块中 } finally { Console.WriteLine("5 无论前面能否发作异常城市跳转到此语句块中"); } Console.WriteLine("6 法式完毕"); Console.ReadKey(); }C# - 异常处理 087  第3张

抛出异常

碰到异常时,利用此体例的施行过程如上图所示,可通过调试查看整个代码施行挨次

4.1 catch中能够指定异常对象,它有3个重要属性

Source:属性暗示招致异常发作的应用法式或对象的名称

Message:供给引起异常的详细信息

StackTrace:此属性供给抛异常的详细信息,并起首显示比来挪用的办法

C# - 异常处理 087  第4张

异常对象

static void Main(string[] args){ string str = null; try { //有可能发作异常的代码 Console.WriteLine(str.ToString()); } catch (Exception ex)//ex 异常对象 { //Exception 几乎能够捕捉所有的异常(理论上) Console.WriteLine("ex.Source\r\n {0}", ex.Source); Console.WriteLine(""); Console.WriteLine("ex.Message\r\n {0}", ex.Message); Console.WriteLine(""); Console.WriteLine("ex.StackTrace\r\n {0}",ex.StackTrace); //1)写入日记 //2)通过throw 向上抛异常(由有处置权限或者专门的"上级"停止处置) } Console.ReadKey();}

利用其他体例中的体例2能够有针对的对某品种型的异常停止捕捉处置

static void Main(string[] args){ string str = null; try { Console.WriteLine(str.ToString()); } //只为演示多catch的用法与原则 //指定捕捉处置空指针异常 //若是发作的异常没有被特定的异常类捕捉 //等同于没有设置异常捕捉 catch (NullReferenceException nullex) { Console.WriteLine("nullex.Message\r\n {0}", nullex.Message); } //指定捕捉处置 除数为0的异常 catch (DivideByZeroException divex) { Console.WriteLine("divex.Message\r\n {0}", divex.Message); } //指定捕捉处置 输入的字符串不合格的异常 catch (FormatException fex) { Console.WriteLine("divex.Message\r\n {0}", fex.Message); } //能够指定许多的异常类型 //Exception 相当于其他所有异常类的"祖宗"类 //用于在上述几个异常类的最初 //Exception 不要写在第一个,不然后面针对特定异常的类就不起感化了 catch (Exception ex) { //能够将上面没有捕捉到的异常捕捉到 Console.WriteLine("ex.Message\r\n {0}", ex.Message); } Console.ReadKey();}

本身捕捉了异常不想停止处置或没有权限停止处置,能够利用throw将异常抛给"上级"停止处置

static void Main(string[] args){ try { M1(); } catch (Exception ex) { //将M1()中的异常信息传递到了ex中 //显示异常类型的信息 Console.WriteLine(ex.Message); //显示抛异常的详细信息 Console.WriteLine(ex.InnerException.ToString()); } Console.ReadKey();}static void M1(){ string str = null; try { Console.WriteLine(str.ToString()); } //处置空指针异常(假设只可能呈现此类异常) catch (NullReferenceException nullex) { //将捕捉的异常信息更好先存储在日记中 //将异常抛给"上级" throw new Exception("出异常了,啦!啦啦!!啦啦啦!!!", nullex); }}C# - 异常处理 087  第5张

向上抛出异常

throw也能够零丁利用,报酬的造造异常;比来关于#鼠头鸭被禁#的事,舆情哗然,编写一个类似验证感词的法式,只要输入了敏感词就抛出异常

static void Main(string[] args){ Console.WriteLine("请输热点敏感词"); string str = Console.ReadLine(); Console.WriteLine(""); if (str.Trim() == "鼠头鸭") { throw new Exception(" (⊙_⊙) !!!"); } else { Console.WriteLine("热点敏感词 {0}", str); } Console.ReadKey();}C# - 异常处理 087  第6张

零丁利用 throw 抛出异常

建议:更好通过逻辑判断(if-else)等语句以削减异常发作的可能性,节省性能损耗

利用异常捕捉机造的好处:不会因为某段功用代码,招致整个法式瓦解(假设是计算器有加减乘除四种功用,除法因为除零抛异常,可暂时利用其他功用)提拔用户体验感(类似拜候的网站,某个网页已"删除",用户找不到,将页面重定向到指定的网页,不会呈现304等不友好的网页)