(34)C#异常
一、异常的层次结构
二、异常格式
异常的一般格式
try { //可能会抛出异常的代码 } catch { //发现错误后会运行这里面的代码 } finally { //写不论是否出现异常都执行的代码 }
格式变体
(1)可以省略finally
try { //可能会抛出异常的代码 } catch { //发现错误后会运行这里面的代码 }
(2)可以有多个catch
每个catch块之间是有顺序的,子类必须写在父类之前,不然无法编译过
try { ... } catch (System.ServiceModel.EndpointNotFoundException) { Console.WriteLine("由于目标计算机积极拒绝,无法连接!"); } catch (Exception ex) { Console.WriteLine("["+DateTime.Now.ToString()+"] - "+ ex.Message); }
(3)不包含catch
try { //可能会抛出异常的代码 } finally { //写不论是否出现异常都执行的代码 }
这种方式不是用来判断异常,而是一钟确保try后执行finally的方式,如果try中有几个出口,这很有用
(4)嵌套try
异常处理可以互相嵌套,在内层找不到对应的处理代码,会向外层找。
而且具MSDN的说法“很多情况下,异常可能不是由代码直接调用的方法引发,而是由调用堆栈中位置更靠下的另一个方法所引发。 在这种情况下,CLR 将展开堆栈,查找是否有方法包含针对该特定异常类型的 catch 块,如果找到这样的方法,就会执行找到的第一个这样的 catch 块。 如果在调用堆栈中的任何位置都没有找到适当的 catch 块,就会终止该进程,并向用户显示一条消息。
static void Main(string[] args) { int n1 = 10; int n2 = 0; int result; try { try { result = n1 / n2; Console.WriteLine("{0}", result); } catch (MemberAccessException e) { Console.WriteLine(e.Message); } finally { Console.WriteLine("finally1"); } } catch (Exception e) { Console.WriteLine(e.Message); } finally { Console.WriteLine("finally2"); } Console.ReadKey(); }
三、Exception
e.ToString() 和 e.Message 的区别
e.ToString()获取的信息包括异常类型和异常详细消息,而e.Message 只是获取了异常的详细消息字符串。
四、throw
throw就是用来抛出异常的,
一个方法 A 中,使用throw语句抛出了一个异常,则调用了 A 方法的地方,必须进行捕捉,或者继续抛出,一直到 main方法,如果main方法也没有进行捕捉,系统则崩溃。
系统碰到没有捕捉的异常,立刻停止,你的弹出对话框的语句,在throw语句的后面,throw语句一执行,调用 A 方法的地方,立刻捕捉到了这个异常,并进行处理,throw后面的语句将不会执行。
throw new Exception(e.Message); throw new Exception("自定义错误信息");
向上传递异常可以只使用throw,但不创建对象,表示抛出catch块的当前异常
catch { throw; }
五、自定义异常
六、异常过滤器 --C# 6以后
新增 when条件
try { } catch (WebException e) when (e.Status == WebExceptionStatus.Timeout) { } catch (WebException e) when (e.Status == WebExceptionStatus.ConnectFailure) { }
七、throw表达式 -- C# 7以后
throw以前只是单独的句子
现在可以是
static void Main(string[] args) { argumentExp(); } public static int argumentExp() =>throw new ArgumentException();