更新:2007 年 11 月

C# 程序员使用 try 块来对可能受异常影响的代码进行分区,并使用 catch 块来处理所产生的任何异常。可以使用 finally 块来执行代码,而无论是否引发了异常。有时需要这样做,因为如果引发了异常,将不会执行 try/catch 构造后面的代码。try 块必须与 catch 或 finally 块一起使用,并且可以包括多个 catch 块。例如:

C# 复制代码
try
{
    // Code to try here.
}
catch (SomeSpecificException ex)
{
    // Code to handle exception here.
    // Only catch exceptions you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}

C# 复制代码
try
{
    // Code to try here.
}
finally
{
    // Code to execute after try here.
}

C# 复制代码
try
{
    // Code to try here.
}
catch (SomeSpecificException ex)
{
    // Code to handle exception here.
}
finally
{
    // Code to execute after try (and possibly catch) here.
}

不带有 catchfinally 块的 try 语句将导致编译器错误。

Catch 块

catch 块可以指定要捕捉的异常类型。此类型称为“异常筛选器”,应该是从 Exception 派生的类型。一般来说,除非您确知如何处理 try 块中可能引发的所有异常,或者在 catch 块的末尾包括一条 throw 语句,否则,不要在 catch 块中指定 Exception

具有不同异常筛选器的多个 catch 块可以串联在一起。多个 catch 块的计算顺序是从顶部到底部,但是,对于所引发的每个异常,都只执行一个 catch 块。与所引发异常的准确类型或其基类最为匹配的第一个 catch 块将被执行。如果没有任何 catch 块指定匹配的异常筛选器,则将执行不带筛选器的 catch 块(如果有的话)。需要将带有最具体的(即派生程度最高的)异常类的 catch 块放在最前面。

当下列条件为真时,应该捕捉异常:

  • 对引发异常的原因有具体的了解,并可实现特定的恢复,例如,捕捉 FileNotFoundException 对象并提示用户输入新的文件名。

  • 可以新建一个更具体的异常并引发该异常。例如:

    C# 复制代码
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch(System.IndexOutOfRangeException e)
        {
            throw new System.ArgumentOutOfRangeException(
                "Parameter index is out of range.");
        }
    }
    
    
  • 部分处理异常。例如,可以使用 catch 块向错误日志中添加项,但随后重新引发该异常,以便对该异常进行后续处理。例如:

    C# 复制代码
    try
    {
        // try to access a resource
    }
    catch (System.UnauthorizedAccessException e)
    {
        LogError(e);  // call a custom error logging procedure
        throw e;      // re-throw the error
    }
    
    

Finally 块

可以使用 finally 块清理在 try 块中执行的操作。如果存在 finally 块,它将在执行完 finallyfinally 块之后执行。finally 块始终会执行,而与是否引发异常或者是否找到与异常类型匹配的 catch 块无关。

可以使用 finally 块释放资源(如文件流、数据库连接和图形句柄),而不用等待由运行时中的垃圾回收器来完成对象。有关更多信息,请参见using 语句(C# 参考)

在此示例中,finally 块用来关闭在 try 块中打开的文件。注意,在关闭文件句柄之前要检查它的状态。如果 try 块没有打开该文件,则文件句柄仍然设置为 null。或者,如果成功打开文件并且没有引发异常,则 finally 块仍将执行,并且将关闭打开的文件。

C# 复制代码
System.IO.FileStream file = null;
System.IO.FileInfo fileinfo = new System.IO.FileInfo("C:\\file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // check for null because OpenWrite
    // might have failed
    if (file != null)
    {
        file.Close();
    }
}

C# 语言规范

有关更多信息,请参见 C# 语言规范中的以下各章节:

  • 16 异常

  • 8.9.5 throw 语句

  • 8.10 try 语句

请参见