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

try-catch ステートメントは、try ブロックと、それに続く catch 句で構成されます。この句にはさまざまな例外のハンドラーを指定します。

解説

例外がスローされると、共通言語ランタイム (CLR: Common Language Runtime) は、この例外を処理する catch ステートメントを検索します。現在実行されているメソッドに catch ブロックが含まれていない場合、CLR は現在のメソッドを呼び出したメソッドを検索します (この方法で、呼び出しスタックの上位を検索していきます)。catch ブロックが見つからない場合、CLR は未処理例外のメッセージをユーザーに表示し、プログラムの実行を停止します。

try ブロックには、例外を発生させる可能性がある保護されたコードが含まれます。ブロックは、例外がスローされるか、ブロックが正常に終了するまで実行されます。たとえば、次の例では null オブジェクトをキャストしようとすると、NullReferenceException 例外が発生します。

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

catch 句は、引数なしで使用してすべての種類の例外をキャッチできますが、この使用方法は推奨しません。通常は、回復方法が判明している例外のみキャッチするのが適切です。したがって、System.Exception から派生したオブジェクト引数を必ず指定します。以下に例を示します。

catch (InvalidCastException e) 
{
}

特定の catch 句は、同一の try-catch ステートメントで複数使用できます。この場合、catch 句は順序どおりにチェックされるため、catch 句の順序が重要になります。例外は、特定性の高い順にキャッチしてください。後のブロックに到達しないように catch ブロックを並べた場合、コンパイラはエラーを発生させます。

catch ステートメントでキャッチされた例外を再びスローするために、catch ブロックでは throw ステートメントを使用できます。次の例では、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);
}

次の例に示すように、指定した条件が true の場合に例外を再スローすることもできます。

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

try ブロック内では、そのブロックで宣言されている変数のみを初期化します。そうしないと、ブロックの実行が完了する前に例外が発生する可能性があります。たとえば、以下のコード例では、変数 n が try ブロック内で初期化されます。この変数を try ブロックの外側にある Write(n) ステートメントで使おうとすると、コンパイラ エラーが発生します。

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」を参照してください。

単一のメソッドの例外

非同期のメソッドは async 修飾子でマークされ、通常は一つ以上を待って式またはステートメントが含まれます。要求の式は TaskTask<TResult>[await] の演算子を追加します。await の式は catchfinally ブロックまたはブロックで発生することはできません。

コントロールが非同期のメソッドの await に到達すると、メソッドの進行状況は、予期されるタスクが完了するまで中断されます。タスクが完了すると、実行には、メソッドで再開できます。詳細については、「Async および Await を使用した非同期プログラミング (C# および Visual Basic)」および「非同期プログラムにおける制御フロー (C# および Visual Basic)」を参照してください。

await が適用される完了したタスクはタスクを返すメソッドの未処理の例外の場合に違反状態になる場合があります。タスクを待機することは例外をスローします。タスクは、Canceled状態に制御が戻るときに、最終的にキャンセル非同期処理できます。取り消されたタスクを待機することは OperationCanceledExceptionをスローします。非同期処理を取り消す方法の詳細については、非同期アプリケーションの微調整 (C# および Visual Basic)を参照してください。

例外をキャッチし、try ブロックのタスクを待機し、catch に関連付けられたブロックで例外をキャッチする。例については、「例」のセクションを参照してください。

タスクは、違反状態にいくつかの例外が、予期した非同期のメソッドに発生したためです。たとえば、タスクは Task.WhenAll呼び出しの結果である場合があります。このようなタスクで待機する場合は、例外の1つが、およびキャッチする例外がキャッチされるかは予測できません。例については、「例」のセクションを参照してください。

使用例

例外を発生させる可能性がある ProcessString メソッドへの呼び出しを含む try ブロックの例を次に示します。catch 句には、メッセージを画面に表示するだけの例外ハンドラーがあります。throw ステートメントが MyMethod の内側から呼び出されると、システムは 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.
     * */

次の例では、2種類の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.
*/

次の例では、非同期のメソッドの例外処理を示します。asyncのタスクからスローする try ブロックに、式を設定 await の例外をキャッチするには、catch ブロックで例外をキャッチします。

コメント例外処理を示す例に throw new Exception の行。タスクの IsFaulted のプロパティはに設定されます True、タスクの Exception.InnerException のプロパティは、例外に設定され、例外は catch ブロックでキャッチされます。

コメントから外すとcancelan非同期処理の動作を示す throw new OperationCancelledException の行。タスクの 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が適用される3種類のタスクが完了すると完了します。

3個のタスクの原因の各例外。catch ブロックは Task.WhenAllによって返されるタスクの Exception.InnerExceptions のプロパティに、例外を反復処理します。

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、キャッチしてスローします (C++)をステートメント

例外処理ステートメント (C# リファレンス)

throw (C# リファレンス)

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

概念

C# プログラミング ガイド

その他の技術情報

C# リファレンス