try-catch (C# リファレンス)try-catch (C# Reference)

try-catch ステートメントは、try ブロックと、それに続く 1 つ以上の catch 句で構成されます。この句にはさまざまな例外のハンドラーを指定します。The try-catch statement consists of a try block followed by one or more catch clauses, which specify handlers for different exceptions.

コメントRemarks

例外がスローされると、共通言語ランタイム (CLR) によって、この例外を処理する catch ステートメントが検索されます。When an exception is thrown, the common language runtime (CLR) looks for the catch statement that handles this exception. 現在実行されているメソッドにそのような catch ブロックが含まれていない場合、CLR は現在のメソッドを呼び出したメソッドを検索し、呼び出し履歴の上位を検索していきます。If the currently executing method does not contain such a catch block, the CLR looks at the method that called the current method, and so on up the call stack. catch ブロックが見つからない場合、CLR はハンドルされていない例外のメッセージをユーザーに表示し、プログラムの実行を停止します。If no catch block is found, then the CLR displays an unhandled exception message to the user and stops execution of the program.

try ブロックには、例外を発生させる可能性がある保護されたコードが含まれます。The try block contains the guarded code that may cause the exception. このブロックは、例外がスローされるか、ブロックが正常に終了するまで実行されます。The block is executed until an exception is thrown or it is completed successfully. たとえば、次の例では null オブジェクトをキャストしようとすると、NullReferenceException 例外が発生します。For example, the following attempt to cast a null object raises the NullReferenceException exception:

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

catch 句は、引数なしで使用してすべての種類の例外をキャッチできますが、この使用方法はお勧めできません。Although the catch clause can be used without arguments to catch any type of exception, this usage is not recommended. 通常は、回復方法が判明している例外のみキャッチします。In general, you should only catch those exceptions that you know how to recover from. したがって、System.Exception から派生したオブジェクト引数を必ず指定します。以下に例を示します。Therefore, you should always specify an object argument derived from System.Exception For example:

catch (InvalidCastException e)   
{  
}  

同一の try-catch ステートメントで、特定の catch 句を複数回使用することもできます。It is possible to use more than one specific catch clause in the same try-catch statement. この場合、catch 句は順序どおりにチェックされるため、catch 句の順序が重要になります。In this case, the order of the catch clauses is important because the catch clauses are examined in order. 例外は、特殊性の高い順にキャッチしてください。Catch the more specific exceptions before the less specific ones. 後のブロックに到達しないような順序で catch ブロックを並べた場合、コンパイラでエラーが発生します。The compiler produces an error if you order your catch blocks so that a later block can never be reached.

処理対象の例外をフィルター処理する方法の 1 つに、catch 引数の使用があります。Using catch arguments is one way to filter for the exceptions you want to handle. また、述語式を使用して例外を確認し、それを処理するかどうかを決定することもできます。You can also use a predicate expression that further examines the exception to decide whether to handle it. 述語式が false を返す場合、ハンドラーの検索が続行されます。If the predicate expression returns false, then the search for a handler continues.

catch (ArgumentException e) when (e.ParamName == "…")  
{  
}  

スタックはフィルターの影響を受けないため、キャッチと再スロー (以下で説明します) には例外フィルターが適しています。Exception filters are preferable to catching and rethrowing (explained below) because filters leave the stack unharmed. 後のハンドラーでスタックをダンプすると、再スローされた最後の場所だけではなく、例外が最初に発生した場所がわかります。If a later handler dumps the stack, you can see where the exception originally came from, rather than just the last place it was rethrown. 例外のフィルター式の一般的な用途の 1 つにログの記録があります。A common use of exception filter expressions is logging. 常に false を返しログも出力する述語関数を作成すれば、処理や再スローの必要なしにそのままの状態で例外をログに記録することができます。You can create a predicate function that always returns false that also outputs to a log, you can log exceptions as they go by without having to handle them and rethrow.

catch ステートメントでキャッチされた例外を再びスローするには、catch ブロックで throw ステートメントを使用できます。A throw statement can be used in a catch block to re-throw the exception that is caught by the catch statement. 次の例では、IOException 例外からソース情報を抽出した後、親メソッドに例外をスローします。The following example extracts source information from an IOException exception, and then throws the exception to the parent method.

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;  
}  

例外をキャッチして、別の例外をスローできます。You can catch one exception and throw a different exception. これを行うには、次の例に示すように、キャッチする例外を内部例外として指定します。When you do this, specify the exception that you caught as the inner exception, as shown in the following example.

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

次の例に示すように、指定した条件が true の場合に例外を再スローすることもできます。You can also re-throw an exception when a specified condition is true, as shown in the following example.

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

try ブロック内では、そのブロックで宣言されている変数のみを初期化します。From inside a try block, initialize only variables that are declared therein. そうしないと、ブロックの実行が完了する前に例外が発生する可能性があります。Otherwise, an exception can occur before the execution of the block is completed. たとえば、次のコードでは、変数 ntry ブロック内で初期化されています。For example, in the following code example, the variable n is initialized inside the try block. この変数を try ブロックの外側にある Write(n) ステートメントで使おうとすると、コンパイラ エラーが発生します。An attempt to use this variable outside the try block in the Write(n) statement will generate a compiler error.

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」を参照してください。For more information about catch, see try-catch-finally.

非同期メソッドの例外Exceptions in Async Methods

非同期メソッドは async 修飾子でマークされ、通常は 1 つ以上の await 式またはステートメントが含まれます。An async method is marked by an async modifier and usually contains one or more await expressions or statements. await 式では、await 演算子が Task または Task<TResult> に適用されます。An await expression applies the await operator to a Task or Task<TResult>.

コントロールが非同期メソッドの await に到達すると、メソッドの進行状況は、待機中のタスクが完了するまで中断されます。When control reaches an await in the async method, progress in the method is suspended until the awaited task completes. タスクが完了すると、メソッドで実行を再開できます。When the task is complete, execution can resume in the method. 詳細については、「Async および Await を使用した非同期プログラミング」と「非同期プログラムにおける制御フロー」を参照してください。For more information, see Asynchronous Programming with async and await and Control Flow in Async Programs.

await が適用される完了したタスクは、タスクを返すメソッドでハンドルされない例外が発生したことが原因で、違反状態になる場合があります。The completed task to which await is applied might be in a faulted state because of an unhandled exception in the method that returns the task. タスクを待機すると例外がスローされます。Awaiting the task throws an exception. タスクを返す非同期処理が取り消された場合に、取り消された状態でタスクを終了することもできます。A task can also end up in a canceled state if the asynchronous process that returns it is canceled. 取り消されたタスクを待機すると、OperationCanceledException がスローされます。Awaiting a canceled task throws an OperationCanceledException. 非同期処理を取り消す方法の詳細については、「非同期アプリケーションの微調整」を参照してください。For more information about how to cancel an asynchronous process, see Fine-Tuning Your Async Application.

例外をキャッチするには、try ブロックでタスクを待機し、関連付けられている catch ブロックで例外をキャッチします。To catch the exception, await the task in a try block, and catch the exception in the associated catch block. 例については、「使用例」のセクションを参照してください。For an example, see the "Example" section.

待機中の非同期メソッドで複数の例外が発生したことが原因で、タスクが違反状態になることがあります。A task can be in a faulted state because multiple exceptions occurred in the awaited async method. たとえば、タスクは Task.WhenAll の呼び出しの結果になることがあります。For example, the task might be the result of a call to Task.WhenAll. このようなタスクを待機すると、1 つの例外のみがキャッチされます。どの例外がキャッチされるかは予測できません。When you await such a task, only one of the exceptions is caught, and you can't predict which exception will be caught. 例については、「使用例」のセクションを参照してください。For an example, see the "Example" section.

Example

例外が発生する可能性がある ProcessString メソッドへの呼び出しを含む try ブロックの例を次に示します。In the following example, the try block contains a call to the ProcessString method that may cause an exception. catch 句には、メッセージを画面に表示するだけの例外ハンドラーがあります。The catch clause contains the exception handler that just displays a message on the screen. throw ステートメントが MyMethod の内側から呼び出されると、システムによって catch ステートメントが検索され、メッセージ Exception caught が表示されます。When the throw statement is called from inside MyMethod, the system looks for the catch statement and displays the message 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.
     * */

Example

次の例では、2 種類の catch ブロックが使用され、特殊性が最も高い最初の例外がキャッチされます。In the following example, two catch blocks are used, and the most specific exception, which comes first, is caught.

特殊性が最も低い例外をキャッチするには、ProcessString の throw ステートメントを throw new Exception() と置き換えることができます。To catch the least specific exception, you can replace the throw statement in ProcessString with the following statement: throw new Exception().

この例で特殊性が最も低い catch ブロックを最初に配置すると、"A previous catch clause already catches all exceptions of this or a super type ('System.Exception')" というエラー メッセージが表示されます。If you place the least-specific catch block first in the example, the following error message appears: 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.
*/

Example

次の例では、非同期メソッドの例外処理を示します。The following example illustrates exception handling for async methods. 非同期タスクからスローされる例外をキャッチするには、try ブロックに await 式を配置し、catch ブロックで例外をキャッチします。To catch an exception that an async task throws, place the await expression in a try block, and catch the exception in a catch block.

例外処理を示すために、この例の throw new Exception 行のコメントを解除します。Uncomment the throw new Exception line in the example to demonstrate exception handling. タスクの IsFaulted プロパティが True に設定され、タスクの Exception.InnerException プロパティが例外に設定され、例外が catch ブロックでキャッチされます。The task's IsFaulted property is set to True, the task's Exception.InnerException property is set to the exception, and the exception is caught in the catch block.

throw new OperationCancelledException 行のコメントを解除して、非同期処理を取り消したときに何が起こるかを示します。Uncomment the throw new OperationCancelledException line to demonstrate what happens when you cancel an asynchronous process. タスクの IsCanceled プロパティが true に設定され、例外が catch ブロックでキャッチされます。The task's IsCanceled property is set to true, and the exception is caught in the catch block. この例に該当しない一部の条件では、タスクの IsFaulted プロパティが true に設定され、IsCanceledfalse に設定されます。Under some conditions that don't apply to this example, the task's IsFaulted property is set to true and IsCanceled is set to 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

Example

次の例では、複数のタスクで複数の例外が発生する可能性がある例外処理について説明します。The following example illustrates exception handling where multiple tasks can result in multiple exceptions. try ブロックは Task.WhenAll の呼び出しで返されるタスクを待機します。The try block awaits the task that's returned by a call to Task.WhenAll. WhenAll が適用される 3 つのタスクが完了すると、このタスクは完了します。The task is complete when the three tasks to which WhenAll is applied are complete.

3 つのタスクでそれぞれ例外が発生します。Each of the three tasks causes an exception. catch ブロックは例外を反復処理します。この例外は、Task.WhenAll で返されたタスクの Exception.InnerExceptions プロパティで見つかります。The catch block iterates through the exceptions, which are found in the Exception.InnerExceptions property of the task that was returned by 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# Language Specification

詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。

関連項目See Also

C# リファレンスC# Reference
C# プログラミング ガイドC# Programming Guide
C# のキーワードC# Keywords
try、throw、catch ステートメント (C++)try, throw, and catch Statements (C++)
例外処理ステートメントException Handling Statements
throwthrow
try-finallytry-finally
方法: 例外を明示的にスローするHow to: Explicitly Throw Exceptions