次の方法で共有


例外処理 (C# プログラミング ガイド)

try ブロックは、例外の影響を受ける可能性があるコードをパーティション分割するために C# プログラマによって使用されます。 関連する catch ブロックは、結果の例外を処理するために使用されます。 finally ブロックには、try ブロックに割り当てられているリソースの解放など、try ブロックで例外がスローされたかどうかに関係なく実行されるコードが含まれます。 try ブロックには、関連付けられた 1 つ以上のcatch ブロック、またはfinally ブロック、またはその両方が必要です。

次の例は、 try-catch ステートメント、 try-finally ステートメント、および try-catch-finally ステートメントを示しています。

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

tryまたはcatch ブロックのないfinally ブロックが原因でコンパイラ エラーが発生します。

catch ブロック

catch ブロックでは、キャッチする例外の種類を指定できます。 型指定は 例外フィルターと呼ばれます。 例外の種類は、 Exceptionから派生する必要があります。 一般に、Exception ブロックでスローされるすべての例外を処理する方法がわかっているか、try ブロックの末尾にthrowステートメントを含めた場合を除き、例外フィルターとしてcatchを指定しないでください。

異なる例外クラスを持つ複数の catch ブロックを連結できます。 catch ブロックはコード内で上から下に評価されますが、スローされる例外ごとに 1 つのcatch ブロックのみが実行されます。 スローされた例外の正確な型または基底クラスを指定する最初の catch ブロックが実行されます。 一致する例外クラスを指定する catch ブロックがない場合は、ステートメントに型がない catch ブロックが選択されます。 最も具体的な (つまり、最も派生した) 例外クラス catch ブロックを最初に配置することが重要です。

次の条件に該当する場合に例外をキャッチします。

  • 例外がスローされる理由を十分に理解していて、かつ特定の回復手段を実装できる (FileNotFoundException オブジェクトをキャッチした場合に、ユーザーに新しいファイル名を入力するよう求めるなど)。
  • より具体的な例外を新規に作成し、スローできる。
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • より多くの処理のために、例外を渡す前に例外を部分的に処理する必要があります。 次の例では、 catch ブロックを使用して、例外を再スローする前にエラー ログにエントリを追加します。
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

例外フィルターを指定して、ブール式を catch 句に追加することもできます。 例外フィルターは、特定の catch 句がその条件が true の場合にのみ一致することを示します。 次の例では、両方の catch 句で同じ例外クラスが使用されますが、別のエラー メッセージを作成するために追加の条件がチェックされます。

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

常に false を返す例外フィルターを使用すると、すべての例外を調べることができますが、処理することはできません。 一般的な用途は、例外をログに記録するためです。

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

LogException メソッドは常にfalseを返します。この例外フィルターを使用するcatch句は一致しません。 catch 句は、 System.Exceptionを使用して一般的にすることができます。以降の句では、より具体的な例外クラスを処理できます。

Finally ブロック

finally ブロックを使用すると、try ブロックで実行されるアクションをクリーンアップできます。 存在する場合、 finally ブロックは、 try ブロックと一致した catch ブロックの後で最後に実行されます。 例外がスローされるか、例外の種類に一致するfinallyブロックが見つかった場合でも、catch ブロックは常に実行されます。

finally ブロックを使用すると、ファイル ストリーム、データベース接続、グラフィックス ハンドルなどのリソースを解放できます。ランタイムのガベージ コレクターがオブジェクトを終了するのを待つ必要はありません。

次の例では、 finally ブロックを使用して、 try ブロックで開かれたファイルを閉じます。 ファイルが閉じられる前に、ファイル ハンドルの状態がチェックされていることに注意してください。 try ブロックでファイルを開くことができない場合でも、ファイル ハンドルには値nullがあり、finally ブロックはファイルを閉じようとしません。 代わりに、ファイルが try ブロックで正常に開かれた場合、 finally ブロックは開いているファイルを閉じます。

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

C# 言語仕様

詳細については、C# 言語仕様例外try ステートメントを参照してください。 言語仕様は、C# の構文と使用法の決定的なソースです。

こちらも参照ください