C# 的异常捕获系统允许开发者将正常代码与异常处理逻辑进行分离。
异常可以表示在软件执行期间出现的各种异常情况,包括内部的和外部的。
外部条件导致的异常:网络故障、权限不足、内存不足、Web服务引发的异常,这些异常通常由操作系统、.NET 运行时或外部应用程序引发;
内部条件导致的异常:软件缺陷、设计的功能故障、传播的外部故障,例如运行时检测到空对象引用、用户输入的无效字符串。
用户自定义的异常类应当继承 Exception 类。
C# 有三种捕获异常的定义:
- try / catch : 捕获并处理
- try / catch / finally : 捕获并处理,同时不管是否捕获到异常,始终执行 finally 语句块
- try / finally : 始终执行 finally 语句块,任何发生的异常都将在 finally 语句块后抛出
异常按照从具体到抽象的顺序被捕获,例如:如果尝试访问一个不存在的文件,CLR 将按照以下顺序查找异常处理器(exception handlers):
- FileNotFoundException
- IOException(FileNotFoundException 的基类)
- SystemException(IOException 的基类)
- Exception(SystemException 的基类)
如果抛出的异常不是派生自要捕获的异常列表,或者不在要捕获的例外列表中,则会将其抛出调用堆栈。
If the exception being thrown does not derive from or is not in the list of exceptions to catch, it is thrown up the call stack.
捕获单个异常:
class ExceptionTest
{
public static void Main(string[] args)
{
try
{
Console.WriteLine(args[0]);
Console.WriteLine(args[1]);
Console.WriteLine(args[2]);
Console.WriteLine(args[3]);
Console.WriteLine(args[4]);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine(e.Message);
}
}
}
捕获多个异常:
class ExceptionTest
{
public static void Main(string[] args)
{
try
{
string fileContents = new StreamReader(@"C:\log.txt").ReadToEnd();
}
catch (UnauthorizedAccessException e) // Access problems
{
Console.WriteLine(e.Message);
}
catch (FileNotFoundException e) // File does not exist
{
Console.WriteLine(e.Message);
}
catch (IOException e) // Some other IO problem.
{
Console.WriteLine(e.Message);
}
}
}
catch 语句中,可以省略异常类型和异常变量名,例如:
try
{
int number = 1/0;
}
catch (DivideByZeroException)
{
// DivideByZeroException
}
catch
{
// some other exception
}
using System;
class ExceptionTest
{
public static void Main(string[] args)
{
SqlConnection sqlConn = null;
try
{
sqlConn = new SqlConnection ( /*Connection here*/ );
sqlConn.Open();
// Various DB things
// Notice you do not need to explicitly close the connection, as .Dispose() does this for you.
}
catch (SqlException e)
{
Console.WriteLine(e.Message);
}
finally
{
if (sqlConn != null && sqlConn.State != ConnectionState.Closed)
{
sqlConn.Dispose();
}
}
}
}
注意到在以上代码中,SqlConnection 对象在 try/catch/finally 之外定义,这是因为在 try/catch 语句块内定义的变量无法在 finally 语句块中被访问。
class ExceptionTest
{
public static void Main(string[] args)
{
SqlConnection sqlConn = null;
try
{
SqlConnection sqlConn = new SqlConnection ( /*Connection here*/ );
sqlConn.Open();
// Various DB bits
}
finally
{
if (sqlConn != null && sqlConn.State != ConnectionState.Closed)
{
sqlConn.Dispose();
}
}
}
}