例外処理ステートメント - throw
、try-catch
、try-finally
、try-catch-finally
例外を処理するには、throw
および try
ステートメントを使用してください。 例外をスローするには、throw
ステートメントを使用してください。 コード ブロックの実行中に発生する可能性がある例外をキャッチして処理するには、try
ステートメントを使用してください。
throw
ステートメント
throw
ステートメントにより例外がスローされます。
if (shapeAmount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}
throw e;
ステートメントでは、e
の結果は System.Exception に暗黙に変換される必要があります。
組み込みの例外クラス (ArgumentOutOfRangeException や InvalidOperationException など) を使用できます。 .NET には、特定の条件で例外をスローするヘルパー メソッド (ArgumentNullException.ThrowIfNull および ArgumentException.ThrowIfNullOrEmpty) も用意されています。 System.Exception から派生する独自の例外クラスを定義することもできます。 詳細については、「例外の作成とスロー」をご覧ください。
catch
ブロック内では、throw;
ステートメントを使用して、catch
ブロックによって処理される例外を再スローできます。
try
{
ProcessShapes(shapeAmount);
}
catch (Exception e)
{
LogError(e, "Shape processing failed.");
throw;
}
Note
throw;
は、Exception.StackTrace プロパティに格納されている例外の元のスタック トレースを保持します。 反対に、throw e;
は e
の StackTrace プロパティを更新します。
例外がスローされると、共通言語ランタイム (CLR) によって、この例外を処理できる catch
ブロック が検索されます。 現在実行されているメソッドにそのような catch
ブロックが含まれていない場合、CLR は現在のメソッドを呼び出したメソッドなどを呼び出し履歴の上まで調べます。 catch
ブロックが見つからない場合、CLR は実行中のスレッドを終了します。 詳細については、C# 言語仕様の「例外の処理方法」セクションを参照してください。
throw
式
throw
は、式として使用することもできます。 これは、次に示すような多くのケースで役立ちます。
条件演算子。 次の例では、
throw
式を使用して、渡された配列args
が空の場合に ArgumentException をスローします。string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument.");
Null 合体演算子。 次の例では、プロパティに割り当てる文字列が
null
の場合、throw
式を使用して ArgumentNullException をスローします。public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); }
式形式のラムダまたはメソッド。 次の例では、
throw
式を使用して InvalidCastException をスローし、DateTime 値への変換がサポートされていないことを示します。DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported.");
try
ステートメント
try
ステートメントは、次のいずれかの形式で使用できます。try-catch
- try
ブロック内のコードの実行中に発生する可能性がある例外を処理する、try-finally
- コントロールが try
ブロックを離れたときに実行されるコードを指定する、try-catch-finally
- 前の 2 つのフォームの組み合わせ。
try-catch
ステートメント
コード ブロックの実行中に発生する可能性がある例外を処理するには、try-catch
ステートメントを使用してください。 try
ブロック内で例外が発生する可能性があるコードを配置します。 対応する catch
ブロックで処理する例外の基本データ型を指定するには、"catch 句" を使用してください。
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
いくつかの catch 句を指定できます。
try
{
var result = await ProcessAsync(-3, 4, cancellationToken);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Processing is cancelled.");
}
例外が発生すると、catch 句は指定した順序で上から下に調べられます。 スローされた例外に対して最大で 1 つの catch
ブロックのみが実行されます。 前の例にも示されているように、例外変数の宣言を省略し、catch 句で例外の種類のみを指定できます。 例外の種類が指定されていない catch 句は、すべての例外と一致し、存在する場合は最後の catch 句である必要があります。
キャッチされた例外を再スローする場合は、次の例に示すように、throw
ステートメントを使用してください。
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{
LogError(e, "Processing failed.");
throw;
}
Note
throw;
は、Exception.StackTrace プロパティに格納されている例外の元のスタック トレースを保持します。 反対に、throw e;
は e
の StackTrace プロパティを更新します。
when
例外フィルター
例外の種類と共に、例外フィルターを指定することもできます。これは、例外をさらに調べて、対応する catch
ブロックがその例外を処理するかどうかを決定します。 次の例に示すように、例外フィルターは、when
キーワードに続くブール式です。
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e) when (e is ArgumentException || e is DivideByZeroException)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
前の例では、例外フィルターを使用して、指定された 2 つの型の例外を処理する 1 つの catch
ブロックを指定しています。
例外フィルターで区別する場合は、同じ例外の種類に対して複数 catch
の句を指定できます。 これらの句の 1 つに例外フィルターがない場合があります。 このような句が存在する場合は、その例外の種類を指定する句の最後である必要があります。
catch
句に例外フィルターがある場合は、その後に表示される catch
句の例外型と同じかそれ以下の派生の例外型を指定できます。 たとえば、例外フィルターが存在する場合、catch (Exception e)
句を最後の句にする必要はありません。
非同期および反復子メソッドの例外
次の例に示すように、非同期関数で例外が発生した場合、関数の結果を待機すると、関数の呼び出し元に伝達されます。
public static async Task Run()
{
try
{
Task<int> processing = ProcessAsync(-1);
Console.WriteLine("Launched processing.");
int result = await processing;
Console.WriteLine($"Result: {result}.");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
// Output:
// Launched processing.
// Processing failed: Input must be non-negative. (Parameter 'input')
}
private static async Task<int> ProcessAsync(int input)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(nameof(input), "Input must be non-negative.");
}
await Task.Delay(500);
return input;
}
反復子メソッドで例外が発生した場合、反復子が次の要素に進むときにのみ呼び出し元に伝達されます。
try-finally
ステートメント
try-finally
ステートメントでは、コントロールが try
ブロックを離れると、finally
ブロックが実行されます。 コントロールは、次の結果として try
ブロックを離れる可能性があります。
- 正常実行、
- ジャンプ ステートメント の実行 (つまり、
return
、break
、continue
、goto
)、または try
ブロックからの例外の伝達。
次の例では、finally
ブロックを使用して、コントロールがメソッドを離れる前にオブジェクトの状態をリセットします。
public async Task HandleRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
finally
{
Busy = false;
}
}
finally
ブロックを使用して、try
ブロックで使用される割り当て済みリソースをクリーン アップすることもできます。
Note
リソースの型が IDisposable または IAsyncDisposable インターフェイスを実装する場合は、using
ステートメントを検討してください。 using
ステートメントを使用すると、制御が using
ステートメントを離れるときに、取得したリソースが確実に破棄されます。 コンパイラは、using
ステートメントを try-finally
ステートメントに変換します。
finally
ブロックの実行は、例外のアンワインド操作がオペレーティング システムによってトリガーされるかどうかに依存します。 finally
ブロックが実行されない唯一のケースは、プログラムの即時終了を伴うものです。 たとえば、このような終了は、Environment.FailFast 呼び出しや OverflowException または InvalidProgramException 例外が原因で発生する場合があります。 ほとんどのオペレーティング システムは、プロセスの停止とアンロードの一環として、リソースの適切なクリーンアップが行われます。
try-catch-finally
ステートメント
try
ブロックの実行中に発生する可能性がある例外の処理、および try
ステートメントからコントロールが離れたときに実行する必要があるコードの指定の両方に try-catch-finally
ステートメントを使います。
public async Task ProcessRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
catch (Exception e) when (e is not OperationCanceledException)
{
LogError(e, $"Failed to process request for item ID {itemId}.");
throw;
}
finally
{
Busy = false;
}
}
catch
ブロックによって例外が処理されると、finally
ブロックはその catch
ブロックの実行後に実行されます (catch
ブロックの実行中に別の例外が発生した場合でも)。 catch
および finally
ブロックの詳細については、それぞれ「try-catch
ステートメント」および「try-finally
ステートメント」を参照してください。
C# 言語仕様
詳細については、「C# 言語仕様」の次のセクションを参照してください。
関連項目
.NET