C# 程序员使用 try 块对可能受异常影响的代码进行分区。 关联的 catch 块用于处理任何生成的异常。
finally块包含运行的代码,无论try
块中是否抛出异常,该代码都会执行,比如释放在try
块中分配的资源。 块 try
需要一个或多个关联的 catch
块,或者一个 finally
块或两者兼有。
以下示例演示语句 try-catch
、 try-finally
语句和 try-catch-finally
语句。
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
// Only catch exceptions that you know how to handle.
// Never catch base class System.Exception without
// rethrowing it at the end of the catch block.
}
try
{
// Code to try goes here.
}
finally
{
// Code to execute after the try block goes here.
}
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}
缺少try
块或catch
块的finally
块会导致编译器错误。
catch 块
块 catch
可以指定要捕获的异常类型。 类型规范称为 异常筛选器。 异常类型应派生自 Exception。 一般情况下,请勿将Exception指定为异常筛选器,除非你知道如何处理可能在try
代码块中引发的所有异常,或者已在throw
代码块末尾包含catch
。
可以将具有不同异常类的多个 catch
块链接在一起。 这些 catch
块在代码中从上到下进行评估,但针对引发的每个异常只执行一个 catch
块。 第一个指定抛出异常的确切类型或基类的 catch
块被执行。 如果没有 catch
块指定了匹配的异常类,则会选择一个没有任何类型的 catch
块(如果语句中存在)。 务必首先定位具有最具体的(即,最底层派生的)异常类的 catch
块。
当以下条件为 true 时,捕获异常:
- 你可以很好地了解引发异常的原因,并且可以实现特定的恢复,例如在捕获 FileNotFoundException 对象时提示用户输入新文件名。
- 可以创建和引发一个新的、更具体的异常。
int GetInt(int[] array, int index) { try { return array[index]; } catch (IndexOutOfRangeException e) { throw new ArgumentOutOfRangeException( "Parameter index is out of range.", e); } }
- 想要先对异常进行部分处理,然后再将其传递以进行更多处理。 在以下示例中,
catch
块用于在重新引发异常之前将条目添加到错误日志。try { // Try to access a resource. } catch (UnauthorizedAccessException e) { // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; }
还可以指定 异常筛选器 ,将布尔表达式添加到 catch 子句。 异常筛选器指示仅当该条件为 true 时,特定的 catch 子句才匹配。 在以下示例中,这两个 catch 子句使用相同的异常类,但会检查额外的条件以创建不同的错误消息:
int GetInt(int[] array, int index)
{
try
{
return array[index];
}
catch (IndexOutOfRangeException e) when (index < 0)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be negative.", e);
}
catch (IndexOutOfRangeException e)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be greater than the array size.", e);
}
}
始终返回 false
的异常筛选器可用于检查所有异常,但不能处理这些异常。 典型的用途是记录异常:
public class ExceptionFilter
{
public static void Main()
{
try
{
string? s = null;
Console.WriteLine(s.Length);
}
catch (Exception e) when (LogException(e))
{
}
Console.WriteLine("Exception must have been handled");
}
private static bool LogException(Exception e)
{
Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
Console.WriteLine($"\tMessage: {e.Message}");
return false;
}
}
LogException
方法始终返回 false
,使用此异常筛选器的 catch
子句均不匹配。 catch 子句可以是通用的,使用 System.Exception,后面的子句可以处理更具体的异常类。
Finally 块
使用 finally
块可以清理在 try
块中执行的操作。 如果存在,finally
块将在 try
块和任何匹配的 catch
块之后最后执行。 无论是否会引发异常或找到匹配异常类型的 finally
块,catch
块都将始终运行。
块 finally
可用于释放文件流、数据库连接和图形句柄等资源,而无需等待运行时中的垃圾回收器完成这些对象。
在以下示例中,该 finally
块用于关闭在 try
块中打开的文件。 请注意,在关闭文件之前,将检查文件句柄的状态。
try
如果块无法打开文件,则文件句柄仍具有值null
,并且finally
该块不会尝试关闭它。 相反,如果文件在块中 try
成功打开,则 finally
块会关闭打开的文件。
FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
file = fileinfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Check for null because OpenWrite might have failed.
file?.Close();
}
C# 语言规范
有关详细信息,请参阅 C# 语言规范中的 Exceptions 和 try 语句。 语言规范是 C# 语法和用法的明确来源。