MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C Sharpの基礎 - 例外処理のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C Sharpの基礎 - 例外処理
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 例外が発生する可能性がある場所では、Try-Catch構文により、その例外をキャッチして適切な処置を施す必要がある。<br> <br><br> == 例外クラスの作成 == ==== 例外クラスを作成する前に ==== 例外クラスを作成する前に、注意すべき点が2つある。<br> * 無闇に例外クラスを作成しない。 *: .NET Frameworkが提供している例外クラスが使用できる場合は、特別な要件がない限りそれを使用する。 *: <br> * 例外クラスをエラー処理以外で使用しない。 *: 例外は、便利な条件分岐構文ではなく、エラー処理のための機構である。 *: また、例外を使用せずに済むような状況(例えば、TryParseメソッドが使用できる等)であれば、使用しないに越したことはない。 *: 例外処理を多用する場合、パフォーマンスに悪影響を及ぼす可能性がある。 <br> ==== 例外クラスの設計方針 ==== * 例外クラス名の末尾は、〜Exceptionとする。 *: このように命名することにより、そのクラスが例外クラスであることが分かる。 *: <br> * 全ての例外クラスは、System.Exceptionを継承する。 *: C#では、System.Exceptionクラスの派生クラスのみをスローすることができる。 *: <br> *: Exceptionクラスから派生していないオブジェクトをキャッチすることもできる。 *: これは、.NET FrameworkのCLRの仕様では、どのようなオブジェクトでもスローすることができるからである。 *: 他の言語との相互運用することを考慮した結果、C#は任意のオブジェクトをキャッチすることができるようになっている。 *: <br> * 例外クラスの継承階層は、できる限り浅くする。 *: 例外クラスの継承階層を深くすると、基底の例外クラスをキャッチするには、様々なエラーに対処しなければならなくなる。 *: また、新たな派生クラスを実装するごとに、基底となる例外クラスを捕捉する全ての動作を検証しなければならなくなる。 *: <br> * 全ての例外クラスはシリアル化可能であるべきである。 *: 以下のような場合、例外クラスをシリアル化する必要がある。 ** ソフトウェアの実行中にスローされた例外オブジェクトが、ソフトウェアドメインの境界を越える場合 ** 例外の内容をログに出力する場合 *: 上記のようなシーンにおいて、例外クラスを使用しない場合もあるが、 *: シリアル化の対応は簡単に行うことができるため、対応することにより、例外クラスの堅牢性が増す。 <br><br> == シリアル化とは == シリアル化とは、オブジェクトをバイトストリームに変換する処理のことである。<br> オブジェクトの現在の状態をファイルに書き出すような処理を行う。<br> <br> シリアル化されたオブジェクトは、テキストファイル等と同様、<br> ストレージに保存してソフトウェアの起動の時に読み込むこと、ネットワーク上に転送することができる。<br> ソフトウェアの設定ファイル等でよく使用されている。<br> <br> また、シリアル化されたバイトストリームを元のオブジェクトに戻す処理のことを、逆シリアル化と呼ぶ。<br> [https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/concepts/serialization/ シリアル化 (C#) | Microsoft Docs]<br> <br><br> ==== 例外クラスの作成 ==== 以下の例では、例外クラスを作成している。<br> 例外クラスは、<code>System.Exception</code>クラスを継承して作成する。<br> <br> 以下の例のように、4つのコンストラクタは、与えられた引数を基底クラス(<code>System.Exception</code>クラス)のコンストラクタに渡す。<br> <br> * 基本の3つのコンストラクタを実装 *: 3番目のコンストラクタは、例外メッセージと共に、例外の原因となる別の例外への参照を<code>innerException</code>に設定して、 *: 例外クラスのインスタンスを初期化するためのものである。 *: <br> * 例外クラスのシリアル化対応 *: <code>SerializableAttribute</code>属性と4番目のコンストラクタにより、例外クラスは、ソフトウェアのドメイン境界を越えることができる。<br> *: <code>SerializableAttribute</code>属性がある全てのクラスは、フォーマッタを使用してシリアル化が可能になる。<br> *: 特に、例外クラスに<code>SerializableAttribute</code>属性がある場合、例外がソフトウェアのドメイン境界を超える時、必要に応じて自動的にシリアル化を行う。<br> *: <br> *: シリアル化されて、別のソフトウェアのドメインからスローされた例外オブジェクトを正しく受け取るためには、元の例外オブジェクトに戻す必要がある。 *: これを、逆シリアル化と呼ぶ。<br> *: これを行うのが、4番目のコンストラクタとなる。<br> *: <br> *: 4番目のコンストラクタは、フォーマッタが呼び出すために存在するため、設計者が明示的に呼び出すことはない。<br> *: また、呼び出されることを避けるため、<code>protected</code>修飾子を付加する。(フォーマッタは、アクセス修飾子に関係なく呼び出すことができる)<br> *: <br> *: 逆シリアル化コンストラクタが<code>public</code>修飾子の場合、任意のコードから不正なデータを渡して例外クラスのインスタンスを生成できる。<br> *: また、例外クラスの継承を禁止する(<code>sealed</code>修飾子を付加する)場合は、逆シリアル化コンストラクタに<code>private</code>修飾子を付加することもできる。<br> <syntaxhighlight lang="c#"> using System; using System.Runtime.Serialization; [Serializable()] // クラスがシリアル化可能であることを示す属性 public class MyException : Exception { public MyException() : base() { } public MyException(string message) : base(message) { } public MyException(string message, Exception innerException) : base(message, innerException) { } // 逆シリアル化コンストラクタ // このクラスの逆シリアル化するために必須 // アクセス修飾子をpublicにしないこと(詳細は後述) protected MyException(SerializationInfo info, StreamingContext context) : base(info, context) { } } </syntaxhighlight> <br><br> == 処理されていない例外をハンドルする == 一般的に、例外が正しくキャッチ(トラップ)されていないというケースは多々ある。<br> <br> その場合、ソフトウェアの実行中において、以下のような.NET Framework標準のエラーダイアログが表示されてしまう。<br> このエラーダイアログは、ユーザにとって理解しにくい。<br> [[ファイル:Catch exception 01.gif|フレームなし|中央]] <br> これを避けるために、.NET Framework標準のエラーダイアログを、自作のエラーダイアログに切り替えたいという要望も多い。<br> <br> ここでは、処理されていない例外を1ヶ所に纏めてハンドルする方法を記載する。<br> この方法により、ハンドルしたメソッド内で独自に作成したエラーダイアログを表示すれば、前述の要望も実現可能である。<br> <br> * Application.ThreadExceptionイベントの活用 *: 処理されなかった例外をハンドルするには、WindowsフォームならApplicationクラス(System.Windows.Forms名前空間)の *: ThreadExceptionイベントをハンドルして処理する。 *: このイベントは、Windowsフォームのメインスレッド(ApplicationクラスのRunメソッドにより実行されるアプリケーションのコンテキスト)内で *: 発生した未処理の例外をハンドルするためのものである。 *: <br> * Thread.GetDomain().UnhandledExceptionイベントの活用 *: では、上記のメイン・スレッド以外のコンテキスト上で発生した例外は、 *: 現在のアプリケーションドメイン(AppDomainクラス(System名前空間)のThread.GetDomainメソッドにより取得できる)の *: UnhandledExceptionイベントで出来る。 *: 例えば、マルチスレッド処理において、メインスレッド以外のスレッドで発生した例外やコンソールで発生した例外等は、 *: 全てこのUnhandledExceptionイベントをハンドルして処理すればよい。 <br> 以下の例では、上記2つのイベントを活用して、未処理の例外を実際に処理している。<br> <syntaxhighlight lang="c#"> using System; using System.Windows.Forms; using System.Threading; namespace WindowsApplication1 { public class Program { [STAThread] static void Main() { // ThreadExceptionイベント・ハンドラを登録する Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException); // UnhandledExceptionイベント・ハンドラを登録する Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(Application_UnhandledException); // メイン・スレッド以外の例外はUnhandledExceptionでハンドル //string buffer = "1"; char error = buffer[2]; // ここで実行されるメインスレッドの例外はApplication_ThreadExceptionでハンドルできる Application.Run(new Form1()); } // 未処理例外をキャッチするイベントハンドラ // (Windowsアプリケーション用) public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) { ShowErrorMessage(e.Exception, "Application_ThreadExceptionによる例外通知です。"); } // 未処理例外をキャッチするイベントハンドラ // (主にコンソール用) public static void Application_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Exception ex = e.ExceptionObject as Exception; if (ex != null) { ShowErrorMessage(ex, "Application_UnhandledExceptionによる例外通知です。"); } } // ユーザー・フレンドリなダイアログを表示するメソッド public static void ShowErrorMessage(Exception ex, string extraMessage) { MessageBox.Show(extraMessage + @" \n――――――――\n\n" + @"エラーが発生しました。開発元にお知らせください\n\n" + @"【エラー内容】\n" + ex.Message + "\n\n" + @"【スタックトレース】\n" + ex.StackTrace); } } } </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:C_Sharp]]
C Sharpの基礎 - 例外処理
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse