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# の構文と使用法の決定的なソースです。
こちらも参照ください
.NET