C#中的异常处理问题try catch finally
作者:知更鸟的码
C#中的异常处理是一种检测和处理代码中运行时错误的机制,由try catch和finaly块提供支持。
.NET框架提供了常见异常的内置类。
程序执行期间发生的异常,它们可能是由于逻辑或系统错误引起的。
如果程序员未提供处理这些异常的机制,则.NET运行时环境将提供默认机制,该机制将终止程序执行。
try..catch..finally
C#提供了三个关键字try,catch和finally,以实现异常处理。
尝试将可能引发异常的语句括起来,而如果存在则catch会处理异常。
finally 可以用于完成任何需要清理的工作。
try..catch..finally块示例:
try { //可能导致异常的语句 } catch(Type x) { //处理异常的语句 } finally { //任何清理代码 }
如果try块内部发生任何异常,则控制权转移到适当的catch块,然后转移到finally块。
但是在C#中,catch和finally块都是可选的。
try块可以与一个或多个catch块或finally块一起存在,也可以与catch和finally块一起存在。
如果try块内没有发生异常,则控件直接转移到finally块。可以说,finally块中的语句总是执行的。
请注意,通过使用break,continue,return或goto将控制权从finally块中移出是错误的。
在C#中,异常不过是Exception类型的对象。Exception 是C#中任何异常的最终基类。
C#本身提供了几个标准异常。甚至用户也可以创建自己的异常类,前提是该异常类应继承自Exception类或Exception类的标准派生类之一,例如DivideByZeroExcpetion到ArgumentException等。
未捕获的异常
以下程序可以通过编译,但在执行过程中将出现错误。
一个数除零是运行时异常,程序终止并显示错误消息。
当前上下文中任何未捕获的异常都会传播到更高的上下文,并寻找适当的catch块来处理它。
如果找不到任何合适的catch块,.NET运行时的默认机制将终止整个程序的执行。
using System; class MyException { public static void Main() { int x = 0; int div = 100/x; Console.WriteLine(div); } }
具有异常处理机制的上述程序的修改形式如下:
在这里,我们使用标准异常类DivideByZeroException的对象来处理由除零引起的异常。
using System; class MyException { public static void Main() { int x = 0; int div = 0; try { div = 100 / x; Console.WriteLine("此行未执行"); } catch (DivideByZeroException) { Console.WriteLine("发生异常"); } Console.WriteLine($"结果为 {div}"); } }
以上代码的结果如下所示:
在上述情况下,程序不会意外终止。
程序控制从try块内发生异常的地方转移到catch块,如果找到任何合适的catch块,则在该catch中执行语句,然后继续正常执行程序语句。
如果存在以下代码的finally块,则finally块中的代码也将被执行。
using System; class MyException { public static void Main() { int x = 0; int div = 0; try { div = 100/x; Console.WriteLine("此行未执行"); } catch(DivideByZeroException) { Console.WriteLine("发生异常"); } finally { Console.WriteLine("Finally块"); } Console.WriteLine($"结果为 {div}"); } }
请记住,在C#中,catch块是可选的。
以下程序在C#中是完全合法的。
using System; class MyException { public static void Main() { int x = 0; int div = 0; try { div = 100/x; Console.WriteLine("此行未执行"); } finally { Console.WriteLine("Finally块"); } Console.WriteLine($"结果为 {div}"); } }
但是在这种情况下,由于没有异常处理catch块,因此执行将终止。
但是在终止程序语句之前,finally块中的语句将得到执行。
在C#中,try块之后必须是catch或finally块。
多个catch块
一个try块可以引发多个异常,可以使用多个catch块来处理。
记住,在通用的catch 块之前应该有更专业的catch 块。否则,编译器将显示编译错误。
using System; class MyException { public static void Main() { int x = 0; int div = 0; try { div = 100 / x; Console.WriteLine("此行未执行"); } catch (DivideByZeroException de) { Console.WriteLine("DivideByZeroException"); } catch (Exception) { Console.WriteLine("Exception"); } finally { Console.WriteLine("Finally块"); } Console.WriteLine($"结果为 {div}"); } }
捕获所有异常
通过提供没有方括号或参数的catch块,我们可以捕获try块内发生的所有异常。
即使我们可以使用带有Exception类型参数的catch块来捕获try块内发生的所有异常,因为在C#中,所有异常都直接或间接地从Exception类继承。
using System; class MyException { public static void Main() { int x = 0; int div = 0; try { div = 100 / x; Console.WriteLine("此行未执行"); } catch { Console.WriteLine("oException"); } Console.WriteLine($"结果为 {div}"); } }
以下程序使用Exception对象处理所有异常。
using System; class MyException { public static void Main() { int x = 0; int div = 0; try { div = 100 / x; Console.WriteLine("此行未执行"); } catch (Exception) { Console.WriteLine("oException"); } Console.WriteLine($"结果为 {div}"); } }
引发异常
在C#中,可以以编程方式引发异常。为此,使用了“ throw”关键字。引发异常的一般形式如下。
throw exception_obj;
例如,以下语句显式引发ArgumentException。
throw new ArgumentException("Exception"); using System; class MyException { public static void Main() { try { throw new DivideByZeroException("Invalid Division"); } catch (DivideByZeroException) { Console.WriteLine("Exception"); } Console.WriteLine("LAST STATEMENT"); } }
重新抛出异常(throw)
我们在catch块内捕获的异常可以通过使用catch块内的关键字throw来重新抛出更高的上下文。
以下程序显示了如何执行此操作。
//C#: Exception Handling: Handling all exceptions using System; class MyClass { public void Method() { try { int x = 0; int sum = 100 / x; } catch (DivideByZeroException) { throw; } } } class MyException { public static void Main() { MyClass mc = new MyClass(); try { mc.Method(); } catch (Exception) { Console.WriteLine("此处捕获异常"); } Console.WriteLine("LAST STATEMENT"); } }
标准例外
异常有两种类型:由执行程序生成的异常和由公共语言运行时生成的异常。
System.Exception是C#中所有异常的基类。多个异常类从该类继承,包括ApplicationException和SystemException。
这两个类构成了大多数其他运行时异常的基础。直接从System.Exception派生的其他异常包括IOException,WebException等。
公共语言运行库引发SystemException。ApplicationException由用户程序而不是运行时引发。
SystemException包括ExecutionEngineException,StaclOverFlowException等。
不建议我们捕获SystemException,也不建议在我们的应用程序中抛出SystemException。
- System.OutOfMemoryException
- System.NullReferenceException
- Syste.InvalidCastException
- Syste.ArrayTypeMismatchException
- System.IndexOutOfRangeException
- System.ArithmeticException
- System.DevideByZeroException
- System.OverFlowException
用户定义的异常
在C#中,可以创建我们自己的异常类。但是Exception必须是C#中所有异常的最终基类。
因此,用户定义的异常类必须从Exception类或其标准派生类之一继承。
using System; //用户自定义的异常 class CustomException : Exception { public CustomException(string str) { Console.WriteLine("用户定义的异常"); } } class MyException { public static void Main() { try { throw new CustomException("RAJESH"); } catch (Exception e) { Console.WriteLine("此处捕获异常" + e.ToString()); } Console.WriteLine("LAST STATEMENT"); } }
设计准则
异常应用于传达特殊情况。不要使用它们来传达预期的事件,例如到达文件末尾。
如果在System命名空间中有一个很好的预定义异常,它描述了异常情况——一个对类的用户有意义的——使用该类而不是定义一个新的异常类,并在消息中放入特定的信息。
最后,如果代码捕获到了将要处理的异常,请在重新抛出该异常之前考虑是否应将异常与其他信息一起包装。
try中的return语句先于finally中的函数执行
代码如下:
static void Main(string[] args) { Console.WriteLine(GetNum()); } public static int GetNum() { int Num=1; try { Console.WriteLine("try"); return Num; } catch (Exception ex) { throw ex; } finally { ++Num; Console.WriteLine("finally"); } }
输出结果如下:
结论
try中的return语句先于finally中的函数执行所以,返回的结果是1, 而不是2。
从运行结果可以看出,return语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行finally语句后才真正开始返回。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。