try-catch(C# 参考)

try-catch 语句由一个 try 块后跟一个或多个 catch 子句构成,这些子句指定不同的异常处理程序。

备注

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

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

object o2 = null;
try
{
    int i2 = (int)o2;   // Error
}

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

catch (InvalidCastException e) 
{
}

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

可在 catch 块中使用 throw 语句以重新引发已由 catch 语句捕获的异常。 以下示例从 IOException 异常中提取源信息,然后向父方法发送异常。

catch (FileNotFoundException e)
{
    // FileNotFoundExceptions are handled here.
}
catch (IOException e)
{
    // Extract some information from this exception, and then 
    // throw it to the parent method.
    if (e.Source != null)
        Console.WriteLine("IOException source: {0}", e.Source);
    throw;
}

可捕获一个异常并引发另一个异常。 执行此操作时,指定将其作为内部异常捕获的异常,如下面的示例所示。

catch (InvalidCastException e) 
{
    // Perform some action here, and then throw a new exception.
    throw new YourCustomException("Put your error message here.", e);
}

还可以在指定的条件为真是重新引发异常,如下面的示例所示。

catch (InvalidCastException e)
{
    if (e.Data == null)
    {
        throw;
    }
    else
    {
        // Take some action.
    }
 }

从内部一个 try 块,只初始化其中声明的变量。 否则,完成对块的执行前,可能会发生异常。 例如,在下面的代码示例中,变量 n 在 try 块内初始化。 如果尝试在 Write(n) 语句中的 try 块外部使用此变量,则会生成编译器错误。

static void Main() 
{
    int n;
    try 
    {
        // Do not initialize this variable here.
        n = 123;
    }
    catch
    {
    }
    // Error: Use of unassigned local variable 'n'.
    Console.Write(n);
}

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

在异步方法的异常

异步方法。异步 修饰符指导和通常包含一个或多个等待表达式或语句。 等待表达式应用 等待 运算符应用于 TaskTask。 await 表达式。catch 不会发生块或 finally 块。

当控件移到在异步方法中 await,方法的进度挂起,直到等待任务完成。 当任务完成后,执行在方法可以恢复。 有关更多信息,请参见使用 Async 和 Await 的异步编程(C# 和 Visual Basic)异步程序中的控制流(C# 和 Visual Basic)

await 是应用已完成的任务可能是处于错误状态由于在返回任务的方法的未经处理的异常。 等待任务引发异常。 任务在一个已取消状态也因此,如果返回它已取消的异步处理。 等待已取消的任务引发 OperationCanceledException。 有关如何取消异步的更多信息,请参见 微调异步应用程序(C# 和 Visual Basic)

捕获异常,等待在 try 的任务块,并捕获在关联的 catch 的异常块。 有关示例,请参见的“示例”一节。

因为多个异常在等待的异步方法,发生的任务可以在已出错状态。 例如,任务可能为调用的结果。Task.WhenAll。 当您等待此类任务时,因此,只有一个捕获到异常和您无法预测哪个异常将捕获。 有关示例,请参见的“示例”一节。

示例

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

    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 块使用的两,因此,最具体的异常,看是,捕获。

若要捕获最少特定异常,则可以使用以下语句替换在 ProcessString 的 throw 语句:throw new Exception()。

如果将最少特定的 catch 首先在该示例中块,将显示以下错误消息:A previous catch clause already catches all exceptions of this or a super type ('System.Exception')。

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 Test.ThrowTest3.ProcessString(String s) ... First exception caught.
*/

下面的示例演示异常处理异步方法的。 要捕捉异步任务引发,在 try 放置 await 表达式的异常块,并捕获在 catch 的异常块。

取消对演示异常处理的示例中的 throw new Exception 行。 任务的 IsFaulted 属性设置为 True,任务的 Exception.InnerException 属性设置为,异常,该异常在 catch 捕获块。

取消注释演示时所发生的 throw new OperationCancelledException 行,当您 cancelan 异步处理。 任务的 IsCanceled 属性设置为 true,并且,异常。catch 捕获块。 这不在特定情况下应用于此示例,任务的 IsFaulted 属性设置为 true,并 IsCanceled 设置为 false。

        public async Task DoSomethingAsync()
        {
            Task<string> theTask = DelayAsync();

            try
            {
                string result = await theTask;
                Debug.WriteLine("Result: " + result);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception Message: " + ex.Message);
            }
            Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
            Debug.WriteLine("Task IsFaulted:  " + theTask.IsFaulted);
            if (theTask.Exception != null)
            {
                Debug.WriteLine("Task Exception Message: "
                    + theTask.Exception.Message);
                Debug.WriteLine("Task Inner Exception Message: "
                    + theTask.Exception.InnerException.Message);
            }
        }

        private async Task<string> DelayAsync()
        {
            await Task.Delay(100);

            // Uncomment each of the following lines to 
            // demonstrate exception handling. 

            //throw new OperationCanceledException("canceled");
            //throw new Exception("Something happened.");
            return "Done";
        }

        // Output when no exception is thrown in the awaited method: 
        //   Result: Done 
        //   Task IsCanceled: False 
        //   Task IsFaulted:  False 

        // Output when an Exception is thrown in the awaited method: 
        //   Exception Message: Something happened. 
        //   Task IsCanceled: False 
        //   Task IsFaulted:  True 
        //   Task Exception Message: One or more errors occurred. 
        //   Task Inner Exception Message: Something happened. 

        // Output when a OperationCanceledException or TaskCanceledException 
        // is thrown in the awaited method: 
        //   Exception Message: canceled 
        //   Task IsCanceled: True 
        //   Task IsFaulted:  False

下面的示例演示异常处理多个任务可能导致多个异常的位置。 try 阻止等待通过对 Task.WhenAll的调用返回的任务。 任务已完成,当 WhenAll 当应用时的三个任务完成。

三个任务原因中的每一个异常。 catch 块通过异常重复,在任务 Exception.InnerExceptions 属性中找到了 Task.WhenAll返回。

public async Task DoMultipleAsync()
{
    Task theTask1 = ExcAsync(info: "First Task");
    Task theTask2 = ExcAsync(info: "Second Task");
    Task theTask3 = ExcAsync(info: "Third Task");

    Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);

    try
    {
        await allTasks;
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Exception: " + ex.Message);
        Debug.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
        foreach (var inEx in allTasks.Exception.InnerExceptions)
        {
            Debug.WriteLine("Task Inner Exception: " + inEx.Message);
        }
    }
}

private async Task ExcAsync(string info)
{
    await Task.Delay(100);

    throw new Exception("Error-" + info);
}

// Output: 
//   Exception: Error-First Task 
//   Task IsFaulted: True 
//   Task Inner Exception: Error-First Task 
//   Task Inner Exception: Error-Second Task 
//   Task Inner Exception: Error-Third Task

C# 语言规范

有关详细信息,请参阅 C# 语言规范。该语言规范是 C# 语法和用法的权威资料。

请参见

任务

如何:显式引发异常

参考

C# 关键字

try、throw 和 catch 语句 (C++)

异常处理语句(C# 参考)

throw(C# 参考)

try-finally(C# 参考)

概念

C# 编程指南

其他资源

C# 参考