更新:2007 年 11 月

try-catch 语句由一个 try 块后跟一个或多个 catch 子句构成,这些子句指定不同的异常处理程序。引发异常时,公共语言运行时 (CLR) 会查找处理此异常的 catch 语句。如果当前执行的方法不包含这样的 catch 块,则 CLR 会查看调用当前方法的方法,然后会遍历调用堆栈。如果找不到 catch 块,则 CLR 会向用户显示一条有关未处理异常的消息并停止执行程序。

try 块包含可能导致异常的保护代码。该块一直执行到引发异常或成功完成为止。例如,下列强制转换 null 对象的尝试引发 NullReferenceException 异常:

 复制代码
object o2 = null;
try
{
    int i2 = (int)o2;   // Error
}

虽然可以使用不带参数的 catch 子句捕捉任何类型的异常,但不推荐这种用法。通常,您应该只捕捉那些您知道如何从中恢复的异常。因此,应该总是指定一个从 System..::.Exception 派生的对象参数。例如:

 复制代码
catch (InvalidCastException e) 
{
}

在同一个 try-catch 语句中可以使用一个以上的特定 catch 子句。这种情况下 catch 子句的顺序很重要,因为会按顺序检查 catch 子句。将先捕获特定程度较高的异常,而不是特定程度较小的异常。如果对 catch 块进行排序以使永远不能达到后面的块,编译器将产生错误。

catch 块中可以使用 throw 语句再次引发已由 catch 语句捕获的异常。例如:

 复制代码
catch (InvalidCastException e) 
{
    throw (e);    // Rethrowing exception e
}

您也可以引发新的异常。此时,请将捕捉的异常指定为内部异常:

 复制代码
catch (InvalidCastException e) 
{
   // Can do cleanup work here.
    throw new CustomException("Error message here.", e);
}

如果要再次引发当前由无参数的 catch 子句处理的异常,则使用不带参数的 throw 语句。例如:

 复制代码
catch
{
    throw;
}

try 块内部时应该只初始化其中声明的变量;否则,完成该块的执行前可能发生异常。例如,在下面的代码示例中,变量 xtry 块内初始化。试图在 Write(x) 语句中的 try 块外部使用此变量时将产生编译器错误:使用了未赋值的局部变量

 复制代码
static void Main() 
{
    int x;
    try 
    {
        // Don't initialize this variable here.
        x = 123;
    }
    catch
    {
    }
    // Error: Use of unassigned local variable 'x'.
    Console.Write(x);
}

有关 catch 的更多信息,请参见 try-catch-finally

示例

在此例中,try 块包含对可能导致异常的 ProcessString 方法的调用。catch 子句包含仅在屏幕上显示消息的异常处理程序。当从 MyMethod 内部调用 throw 语句时,系统查找 catch 语句并显示 Exception caught 消息。

C# 复制代码
    class TryFinallyTest
{
    static void ProcessString(string s)
    {
        if (s == null)
        {
            throw new ArgumentNullException();
        }
    }

    static void Main()
    {
        string s = null; // For demonstration purposes.

        try
        {            
            ProcessString(s);
        }

        catch (Exception e)
        {
            Console.WriteLine("{0} Exception caught.", e);
        }
    }
}
    /*
    Output:
    System.ArgumentNullException: Value cannot be null.
       at TryFinallyTest.Main() Exception caught.
     * */


此例使用了两个 catch 语句。最先出现的最特定的异常被捕获。

C# 复制代码
class ThrowTest3
{
    static void ProcessString(string s)
    {
        if (s == null)
        {
            throw new ArgumentNullException();
        }
    }

    static void Main()
    {
        try
        {
            string s = null;
            ProcessString(s);
        }
        // Most specific:
        catch (ArgumentNullException e)
        {
            Console.WriteLine("{0} First exception caught.", e);
        }
        // Least specific:
        catch (Exception e)
        {
            Console.WriteLine("{0} Second exception caught.", e);
        }
    }
}
/*
 Output:
System.ArgumentNullException: Value cannot be null.
   at TryFinallyTest.Main() First exception caught.
*/

在前面的示例中,如果从具体程度最低的 catch 子句开始,您将收到以下错误信息:

A previous catch clause already catches all exceptions of this or a super type ('System.Exception')

但是,若要捕获特定程度最小的异常,请使用下面的语句替换 throw 语句:

throw new Exception();

C# 语言规范

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

  • 5.3.3.13 Try-catch 语句

  • 8.10 try 语句

  • 16 异常

请参见

任务

如何:显式引发异常

概念

参考

The try, catch, and throw Statements

其他资源