概要

例外の単元は当然くるよな。これまでぼくが読んでみろりHPにまとめた、例外についての tips は以下のとおり。こうしてみると、いろんな技術書読んだなあ。

自作モジュール(API)では自分用の例外を定義しよう。
自作例外を用意すると、 API コードのバグを発見しやすくなる。自分で意図した例外と標準的な例外を分けて掴まえることができるからだ。掴まえた例外が自作例外でなければ、それは起こすつもりではなかった例外ということになり、 API コードのバグだということがわかるのだ。
Brett Slatkin『Effective Python』その7 協働作業

 

関数返り値にNoneを設定するのはヤメて、例外を飛ばせ。
Brett Slatkin『Effective Python』その2 関数

 

例外を投げたあと、メソッドの呼び元が例外から回復することを考慮すること
例外を投げたオブジェクトは元の状態へ戻るのが好ましい。そういうのをエラーアトミック性っていうんだって。
Joshua Block『Effective Java 第二版』 後半

 

トラッシュ(めちゃくちゃ)にさせるんじゃなくクラッシュ(停止)させること
プログラム内でエラーが起きたら即座に例外飛ばして停止させること。
Andrew Hunt and David Thomas『達人プログラマー』

今回のオライリー C# は、これまでの読書にはたして沿うだろうか?

では流し読むぞ。

 

流し読みノート

try 文は基本 Python と同じっぽい

try
{
    throw new IOException();
}
catch (FileNotFoundException x)
{

}
catch (IOException x)
{
    // 例外を再スローするときは throw x ではなくてこう。
    // throw x しちゃうと新たな例外だと思って位置を再設定しちゃうから。
    throw;
}
finally
{

}

 

例外は Windows イベントログで見れる

  • 例外が発生すると WER(Windows Error Reporting)が例外の情報を「バケット値」として取得。これを Windows イベントログに書き込む。
  • イベントログは Windows のイベントビューアアプリで見れる。
  • イベントログに書き込む以外にも、クラッシュレポートをアップロードしたりできる。これは Windows のユーザが自分で設定できる。
    • 「このクラッシュレポートを送信しますか?」みたいなのってソレだったのかな?

 

滅びの呪文 FailFast

  • Environment.FailFast メソッド使うと CLR はメッセージをイベントログに書き込み即座に終了する。

 

どの例外を使おうか

.NET Framework はたくさんの例外型を用意しているから、そんなかから選ぼう。しかし知っておくべき重要な例外型もある。

  • ArgumentException, ArgumentNullException, ArgumentOutOfRangeException, CultureNotFoundException: 適切でない引数。
  • AggregateException: 例外を溜めといて、最後にすべて報告したいときに。
  • InvalidOperationException: オブジェクトが処理できない何かを行おうとしたときに。
  • NotImplementedException, NotSupportedException: 名前のまんまかな。

クラスライブラリに適切な例外がなければカスタム例外を作ろう。適切というのは、「エラーが何か適切でないという事実だけでなく、より多くの伝えるべきことをもつ場合」だ。これ、『Effective Python』に書いてあった「ルート例外を作ろう」っていうハナシと矛盾するね。

 

カスタム例外の作り方

  • まずどの Exception から派生させようか? というハナシになる。
  • クラスライブラリのガイドラインに ApplicationException, SystemException は避けよとある。
  • ふつーは Exception 派生でよい。
  • Exception にはパラメータ(引数)のないコンストラクタがあるけど、それは使うな。 string でエラーを説明すること。
  • あと ExceptionISerializable だけど、シリアライズ可にする必要はない。アプリケーションドメインをまたがって例外を使いたいときに実装しよう。
  • カスタム例外を作るときは、メッセージをもつコンストラクタとふつーに string を受け付けるコンストラクタを作るのが一般的。以下に示す。
public class DeviceNotReadyException : InvalidOperationException
{
    // メッセージをもつコンストラクタというのはこれのこと。
    public DeviceNotReadyException(DeviceStatus status)
        : this("デバイスは準備中状態でないとだめ", status)
    {
    }
    // ふつーに string を受け付けるコンストラクタというのはこれのこと。
    public DeviceNotReadyException(string message, DeviceStatus status)
        : base(message)
    {
        Status = status;
    }
    public DeviceNotReadyException(string message, DeviceStatus status, Exception innerException)
        : base(message, innerException)
    {
        Status = status;
    }
    public DeviceStatus Status { get; private set;}
}
public enum DeviceStatus
{
    Disconnected,
    Initializing,
    Failed,
    Ready,
}

 

未処理の例外はフレームワークにキャッチしてもらおう

  • ASP.NET なら global.aspx 無いの Application_Error イベント。
  • WPF なら Application クラスの DispatcherUnhandledException。
  • Windows フォームは ThreadException をもつ Application クラス。

 

なんかよくわからんけど VS が反応できない例外

デバッガメニューの例外ダイアログからそのあたりはいじれるらしい。しらん。

 

非同期例外

  • ここでいう非同期とは、非同期プログラミングとか async とは関係ない。
  • 例外を引き起こすものが、そのとき実行していたコードとは関係ないことを意味している。どういうことやねん。
  • たとえば……
    • ThreadAbortException
    • OutOfMemoryException
    • StackOverflowException
    • ああ、このラインナップをみれば「例外を起こすものが実行コードと関係ない」の意味がわかるね。
  • こういうのが発生したら、基本は諦めよう。こういう例外からの回復は困難で、プロセスをクラッシュさせて再起動するほうが簡単。

 

小休憩

  • 基本的には Python の知識をそのまま使えばいいね。
  • ただカスタム例外の作り時が違うね。まあ、カスタム例外を作るときはエラーメッセージを予めコンストラクタに実装しておこう、というのは実践しよう。
    • enum との組み合わせもなるほどだった。
  • ほかはもうなんか、 Windows とベッタリであるっていうことだけ分かった。