例外の作成とスロー (C# プログラミング ガイド)
更新 : 2007 年 11 月
例外は、プログラムの実行中にエラーが発生したことを示すために使用されます。エラーを説明する例外オブジェクトは、作成後、throw キーワードによりスローされます。ランタイムは、対応する最も近い例外ハンドラを検索します。
次の条件の 1 つ以上が該当する場合、プログラマは例外をスローする必要があります。
メソッドが、定義されている機能を完了できない場合。
たとえば、メソッドのパラメータの値が無効な場合は、次のような例外をスローします。
static void CopyObject(SampleClass original) { if (original == null) { throw new System.ArgumentException("Parameter cannot be null", "original"); } }
オブジェクトの状態に照らして不適切な呼び出しがオブジェクトに対して行われた場合。
1 例として、読み取り専用ファイルに書き込もうとした場合が挙げられます。オブジェクトの状態により操作が許可されない場合、InvalidOperationException のインスタンスまたはこのクラスの派生に基づくオブジェクトがスローされます。InvalidOperationException オブジェクトをスローするメソッドの例を次に示します。
class ProgramLog { System.IO.FileStream logFile = null; void OpenLog(System.IO.FileInfo fileName, System.IO.FileMode mode) {} void WriteLog() { if (!this.logFile.CanWrite) { throw new System.InvalidOperationException("Logfile cannot be read-only"); } // Else write data to the log and return. } }
メソッドの引数が原因で例外が発生した場合。
この場合、元の例外をキャッチして、ArgumentException インスタンスを作成する必要があります。元の例外は、InnerException パラメータとして ArgumentException のコンストラクタに渡す必要があります。
static int GetValueFromArray(int[] array, int index) { try { return array[index]; } catch (System.IndexOutOfRangeException ex) { System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex); throw argEx; } }
例外には、StackTrace というプロパティがあります。この文字列には、現在の呼び出し履歴にあるメソッドの名前と、各メソッドについて例外がスローされたファイル名と行番号が含まれます。StackTrace オブジェクトは、throw ステートメントの位置で共通言語ランタイム (CLR: Common Language Runtime) によって自動的に作成されるため、例外は、スタック トレースが開始される位置からスローする必要があります。
例外にはいずれも Message というプロパティがあります。この文字列は、例外の原因を説明するように設定する必要がありますセキュリティ上重要な情報をメッセージ テキストに含めないように注意してください。Message に加え、ArgumentException には ParamName というプロパティがあります。このプロパティは、例外がスローされる原因になった引数の名前に設定する必要があります。プロパティ Set アクセス操作子の場合は、ParamName を value に設定する必要があります。
パブリック メソッドとプロテクト メソッドは、意図された機能を完了できない場合に例外をスローする必要があります。スローされる例外クラスは、エラー状態に最も明確に適合する例外である必要があります。これらの例外は、クラス機能の一部として記述する必要があり、派生クラスや元のクラスの更新では、下位互換性を確保するために同じ動作を保持する必要があります。
例外をスローする場合に避けなければならないこと
例外をスローする場合に避けなければならないことを以下に示します。
例外を通常の実行の一部として使用してプログラムのフローを変えることをしないようにしてください。例外は、エラー状態の報告と処理のためだけに使用してください。
そして、戻り値またはパラメータとして返されるのではなく、スローされるようにしてください。
独自のソース コードから System.Exception、System.SystemException、System.NullReferenceException、または System.IndexOutOfRangeException を意図的にスローしないでください。
デバッグ モードでスローできるがリリース モードでスローできない例外を作成しないでください。開発フェーズで実行時エラーを識別するには、代わりに Debug Assert を使用します。
例外クラスの定義
プログラムでは、System 名前空間で定義済みの、上記以外の例外クラスをスローできます。また、ApplicationException から派生させて固有の例外クラスを作成することもできます。派生クラスでは、少なくとも 4 つのコンストラクタを定義する必要があります。1 つ目は既定のコンストラクタ、2 つ目はメッセージ プロパティを設定するコンストラクタ、3 つ目は Message と InnerException の両方のプロパティを設定するコンストラクタです。そして 4 つ目のコンストラクタは、例外をシリアル化するのに使用します。新しい例外クラスは、シリアル化できるクラスにする必要があります。次に例を示します。
[Serializable()]
public class InvalidDepartmentException : System.Exception
{
public InvalidDepartmentException() { }
public InvalidDepartmentException(string message) { }
public InvalidDepartmentException(string message, System.Exception inner) { }
// Constructor needed for serialization
// when exception propagates from a remoting server to the client.
protected InvalidDepartmentException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) { }
}
新しいプロパティを例外クラスに追加するのは、それらが提供するデータが例外を解決する上で有効な場合に限定する必要があります。新しいプロパティを派生例外クラスに追加した場合は、ToString() をオーバーライドして追加情報を返す必要があります。
C# 言語仕様
詳細については、「C# 言語仕様」の次のセクションを参照してください。
8.9.5 throw ステートメント
8.10 try ステートメント
16 例外