C#异常总结
- 定义
- Try语句
- 异常类
- 创建用户自定义异常
- 搜索调用栈的示例
- 异常抛出
定义
程序中的运行时错误,它违反一个系统约束或应用程序约束,或出现了在正常操作时未预料的情形。
Try语句
指明被异常保护的代码块,并提供代码以处理异常。try由三部分组成:try…catch finally.
try:包含正被异常保护的代码
catch:含有一个或多个catch子句,这些是处理异常的代码块,也叫做异常处理程序
finally:含有在所有情况下都要被执行的代码,无论有没有异常发生
异常类
BCL定义了许多类,每一个类代表一个指定的异常类型,当一个异常发生时,CLR:
- 创建该类型的异常对象
- 寻找适当的catch子句以处理 它
所有异常类都从根本上派生自system.exception类,异常继承层次如下
异常类类型包括:基类:System.Exception;系统级异常:System.SystemException;应用程序级异常:System.ApplicationException。
(1).由System.SystemException派生的异常类型:
System.AccessViolationException | 在试图读写受保护内存时引发的异常。 |
---|---|
System.ArgumentException | 在向方法提供的其中一个参数无效时引发的异常。 |
System.Collections.Generic.KeyNotFoundException | 指定用于访问集合中元素的键与集合中的任何键都不匹配时所引发的异常。 |
System.IndexOutOfRangeException | 访问数组时,因元素索引超出数组边界而引发的异常。 |
System.InvalidCastException | 因无效类型转换或显示转换引发的异常。 |
System.InvalidOperationException | 当方法调用对于对象的当前状态无效时引发的异常。 |
System.InvalidProgramException | 当程序包含无效Microsoft中间语言(MSIL)或元数据时引发的异常,这通常表示生成程序的编译器中有bug。 |
System.IO.IOException | 发生I/O错误时引发的异常。 |
System.NotImplementedException | 在无法实现请求的方法或操作时引发的异常。 |
System.NullReferenceException | 尝试对空对象引用进行操作时引发的异常。 |
System.OutOfMemoryException | 没有足够的内存继续执行程序时引发的异常。 |
System.StackOverflowException | 挂起的方法调用过多而导致执行堆栈溢出时引发的异常。 |
(2).由System.ArgumentException派生的异常类型:
System.ArgumentNullException | 当将空引用传递给不接受它作为有效参数的方法时引发的异常。 |
---|---|
System.ArgumentOutOfRangeException | 当参数值超出调用的方法所定义的允许取值范围时引发的异常。 |
(3).由System.ArithmeticException派生的异常类型:
System.DivideByZeroException | 试图用零除整数值或十进制数值时引发的异常。 |
---|---|
System.NotFiniteNumberException | 当浮点值为正无穷大、负无穷大或非数字(NaN)时引发的异常。 |
System.OverflowException | 在选中的上下文中所进行的算数运算、类型转换或转换操作导致溢出时引发的异常。 |
(4).由System.IOException派生的异常类型:
System.IO.DirectoryNotFoundException | 当找不到文件或目录的一部分时所引发的异常。 |
---|---|
System.IO.DriveNotFoundException | 当尝试访问的驱动器或共享不可用时引发的异常。 |
System.IO.EndOfStreamException | 读操作试图超出流的末尾时引发的异常。 |
System.IO.FileLoadException | 当找到托管程序却不能加载它时引发的异常。 |
System.IO.FileNotFoundException | 试图访问磁盘上不存在的文件失败时引发的异常。 |
System.IO.PathTooLongException | 当路径名或文件名超过系统定义的最大长度时引发的异常。 |
(5).其他常用异常类型:
ArrayTypeMismatchException | 试图在数组中存储错误类型的对象。 |
---|---|
BadImageFormatException | 图形的格式错误。 |
DivideByZeroException | 除零异常。 |
DllNotFoundException | 找不到引用的dll。 |
FormatException | 参数格式错误。 |
MethodAccessException | 试图访问私有或者受保护的方法。 |
MissingMemberException | 访问一个无效版本的dll。 |
NotSupportedException | 调用的方法在类中没有实现。 |
PlatformNotSupportedException | 平台不支持某个特定属性时抛出该错误。 |
创建用户自定义异常
自定义的异常类派生自ApplicationException类
class Program
{
static void Main(string[] args)
{
//用户自定义的异常类是派生自ApplicationException类
Temperture temp = new Temperture();
try
{
temp.showTemp();
}
catch(TempIsZeroException e)
{
Console.WriteLine("TempIsZeroException:{0}", e.Message);
}
Console.ReadKey();
}
}
//创建自定义异常
public class TempIsZeroException:ApplicationException
{
public TempIsZeroException(string message):base(message)
{
}
}
public class Temperture
{
int temperature = 0;
public void showTemp()
{
if(temperature==0)
{
throw (new TempIsZeroException("Zero Temperature found"));
}
else
{
Console.WriteLine("Temperature:{0}", temperature);
}
}
}
搜索调用栈的示例
class Program
{
static void Main(string[] args)
{
Myclass MCLs = new Myclass();
try
{
MCLs.A();
}
catch(DivideByZeroException e)
{
Console.WriteLine("catch clause in Main()");
}
finally
{
Console.WriteLine("finally clause in Main()");
}
Console.WriteLine("After try statement in Main");
Console.WriteLine("----------------------keep runing");
Console.ReadKey();
}
}
class Myclass
{
public void A()
{
try
{
B();
}
catch(System.NullReferenceException)
{
Console.WriteLine("catch clause in A()");
}
finally
{
Console.WriteLine("finally clause in A()");
}
}
void B()
{
int x = 10, y = 0;
try
{
x /= y;
}
catch(System.IndexOutOfRangeException)
{
Console.WriteLine("catch clause in B()");
}
finally
{
Console.WriteLine("finally clasue in B()");
}
}
}
- Main调用A,调用B,B遇到一个DivideByZeroExceprion异常。
- 系统检查B的catch段寻找匹配的catch子句。虽然它有一个Index0ut0fRangeException的子句,但没有DivideByZerException的。
- 系统然后延着调用栈向下移动并检查A的catch段,在那里它发现A也没有匹配的atch子句
- 系统继续延调用栈向下,并检查Main的catch子句部分,在那里它发现Main确实有一个DivideByZeroException的catch子句。
- 尽管匹配的catch子句现在被定位了,但并不执行。相反,系统回到栈的顶端,执行B的finally子句,并把B从调用栈中弹出。
- 系统移动到A,执行它的fina]1y子句,并把A从调用栈中弹出。
- 最后,Main的匹配catch子句被执行,接着是它的fina11y子句。然后执行在Main的try语句结尾之后继续。
异常抛出
可以使用throw语句显式引发一个异常,语法如下:
throw ExceptionObject
class Program
{
static void Main(string[] args)
{
//带对象的异常抛出
string s = null;
Myclass.PrintArg(s);
Myclass.PrintArg("hello world");
Myclass01.PrintArg(s);
Console.ReadKey();
}
}
class Myclass
{
public static void PrintArg(string arg)
{
try
{
if(arg==null)
{
ArgumentNullException myEx = new ArgumentNullException("arg");
throw myEx;
}
}
catch (ArgumentNullException e)
{
Console.WriteLine("Message:{0}", e.Message);
}
}
}
class Myclass01
{
public static void PrintArg(string arg)
{
try
{
try
{
if(arg == null)
{
ArgumentNullException myEx = new ArgumentNullException("arg");
throw myEx;
}
Console.WriteLine(arg);
}
catch(ArgumentNullException e)
{
Console.WriteLine("Inner catch:{0}", e.Message);
throw;//重新抛出异常,没有附加参数
}
}
catch
{
Console.WriteLine("Outer catch:Handling an Exception.");
}
}
}
本文参考C#图解教程以及博文C#处理Exception的常用方法总结