例外の処理とスロー

アプリケーションには、実行中に発生するエラーを一貫した方法で処理する機能が必要です。 共通言語ランタイムでは、統一された方法でアプリケーションに対してエラーを通知するモデルが用意されています。 .NET Framework のすべての操作で、例外をスローしてエラーを通知します。

このトピックは、次のセクションで構成されています。

  • .NET Framework の例外

  • 例外と 従来のエラー処理方法

  • ランタイムによる例外の管理

  • ランタイム例外のフィルター処理

  • 関連トピック

  • 参照

.NET Framework の例外

例外とは、実行プログラムが遭遇するエラー状態や予期しない動作のことです。 例外が発生する原因には、作成したコードや呼び出したコード (共有ライブラリなど) での違反、オペレーティング システム リソースが使用できない状況、共通言語ランタイムにより検出された予期しない状況 (たとえば、コードを検証できない) などがあります。 このようなエラーには、アプリケーションによって回復できるエラーと回復できないエラーがあります。 ほとんどのアプリケーション例外からは回復できますが、ほとんどのランタイム例外からは回復できません。

.NET Framework では、例外は System.Exception クラスの継承オブジェクトです。 例外は、問題が発生したコード領域からスローされます。 アプリケーションが例外を処理するか、またはプログラムが終了するまで、例外はスタックに渡されます。

ページのトップへ

例外と従来のエラー処理方法

従来のプログラミング言語のエラー処理モデルは、エラーを検出してそれに対応するハンドラーを検索する言語固有の方法か、オペレーティング システムのエラー処理方法のいずれかに基づいていました。 ランタイムで実装される例外処理には、次の機能があります。

  • 例外を生成する言語や、例外を処理する言語に依存せずに例外を処理します。

  • 例外を処理するときに特定の言語の構文を必要とせず、各言語で固有の構文を定義できます。

  • プロセス間で例外をスローしたり、マシン境界を越えて例外をスローしたりできます。

リターン コードなどの他のエラー通知方法に比べ、例外を使用したエラー通知方法には多くの利点があります。 エラーは必ず通知されます。 エラー発生後に無効な値がシステム内に反映されません。 リターン コードを確認する必要がありません。 例外処理コードを簡単に追加でき、これによりプログラムの信頼性が向上します。 ランタイムでの例外処理は、Windows ベースの C++ 例外処理よりも高速です。

例外スレッドがマネージ コード ブロックとアンマネージ コード ブロックを定期的に走査するため、ランタイムはマネージ コードとアンマネージ コードのいずれでも例外をスローまたはキャッチできます。 アンマネージ コードには、C++ スタイルの SEH 例外や COM ベースの HRESULTS などを含めることができます。

ランタイムによる例外の管理

ランタイムは、例外オブジェクトとプロテクト ブロック コードに基づいた例外処理モデルを使用しています。 例外が発生すると、その例外を表す Exception オブジェクトが作成されます。

ランタイムにより、各実行可能ファイルに対して例外情報テーブルが作成されます。 実行可能ファイルの各メソッドに対して、例外情報テーブルの例外処理情報配列が関連付けられます。この配列は空のこともあります。 配列の各エントリは、プロテクト ブロック コード、コードに関連付けられている例外フィルター、および例外ハンドラー (catch ステートメント) を記述します。 例外テーブルは非常に効率的な機能であり、例外が発生しない状況では、プロセッサ時間やメモリの使用量などパフォーマンスへの影響はありません。 例外が発生した場合だけにこれらのリソースが使用されます。

例外情報テーブルに示されるプロテクト ブロックに対する 4 種類の例外ハンドラーを次に示します。

  • finally ハンドラー。このハンドラーは、通常の制御フローまたは未処理の例外によってブロックが終了するたびに実行されます。

  • フォールト ハンドラー。このハンドラーは、例外が発生した場合に実行されます。通常の制御フロー完了時には実行されません。

  • タイプ フィルター ハンドラー。このハンドラーは、指定されているクラスまたはその派生クラスの例外をすべて処理します。

  • ユーザー フィルター ハンドラー。このハンドラーは、関連付けられているハンドラーで例外を処理するか、または次のプロテクト ブロックに例外を渡すかどうかを判別するために、ユーザーが指定したコードを実行します。

各言語では、言語の仕様に従って上記の例外ハンドラーが実装されます。 たとえば、Visual Basic では、catch ステートメントの When キーワードを使用した変数比較によって、ユーザー フィルター ハンドラーへのアクセスを実現します。C# では、ユーザー フィルター ハンドラーは実装されません。

例外が発生すると、ランタイムは次の 2 段階の処理を実行します。

  1. 次の 2 つの条件に一致する 1 番目のプロテクト ブロックの配列を検索します。

    • 現在実行中の命令が含まれている領域を保護している。

    • 例外ハンドラー、または例外を処理するフィルターのいずれかが含まれている。

  2. 上の条件に一致するブロックの配列が検出されると、ランタイムは例外を記述する Exception オブジェクトを作成します。 ランタイムは次に、例外が発生したステートメントと例外を処理するステートメントの間にある finally ステートメントと fault ステートメントをすべて実行します。 例外ハンドラーの順序は重要です。最も内側の例外ハンドラーが最初に評価されます。 また、例外ハンドラーは例外をキャッチするルーチンのローカル変数とローカル メモリへアクセスできますが、例外がスローされた時点の中間値はすべて失われることにも注意してください。

    現在のメソッドで一致するブロックが検出されないと、ランタイムはスタック内で現在のメソッドの呼び出し元を 1 つずつ検索します。 どの呼び出し元にも一致するブロックがない場合は、デバッガーが例外へアクセスできます。 デバッガーが例外にアタッチされていない場合には、AppDomain.UnhandledException イベントが発生します。 このイベントのリスナーがない場合、ランタイムはスタック トレースをダンプし、アプリケーションを終了します。

ページのトップへ

ランタイム例外のフィルター処理

キャッチする例外や処理する例外を、例外の種類やユーザー定義条件に従ってフィルター処理できます。

タイプ フィルター ハンドラーは、特定の種類の例外 (またはこの例外から派生したクラス) を管理します。 特定の例外をキャッチするタイプ フィルター ハンドラーを次のコード例に示します。このコード例では、FileNotFoundException がキャッチされます。

Catch e As FileNotFoundException
    Console.WriteLine("[Data File Missing] {0}", e)
catch (FileNotFoundException e)
{
    Console.WriteLine("[Data File Missing] {0}", e);
}
catch (FileNotFoundException^ e)
{
    Console::WriteLine("[Data File Missing] {0}", e);
}

ユーザー フィルター例外ハンドラーは、独自に定義された例外の条件に基づいて例外をキャッチおよび処理します。 この例外フィルター処理の詳細については、「catch ブロックでの特定の例外の使用」を参照してください。

ページのトップへ

関連トピック

タイトル

説明

Exception クラスとプロパティ

例外オブジェクトの要素について説明します。

例外階層

ほとんどの例外の派生元である例外について説明します。

例外処理の基本事項

catch、throw、finally の各ステートメントを使用した例外の処理方法について説明します。

例外処理の実施

推奨される例外処理方法について説明します。

COM 相互運用の例外の処理

アンマネージ コードでスローおよびキャッチされる例外の処理方法について説明します。

方法: HRESULT に例外を割り当てる

マネージ コードとアンマネージ コードとの間での例外のマップについて説明します。

ページのトップへ

参照

System.Exception

System.ApplicationException

System.SystemException