Diary Blog of Dary

temtanが書いた文章

「他の例外クラスを継承しただけの例外クラスを作らない」に不同意の理由

オブジェクト倶楽部、コーディング規約の会の「C# コーディング標準」の駄目なところ - ぐるぐる~

これは多分、中身が空っぽな例外クラスを大量生産してるんだと予想。

中身がない例外クラスを作る目的としては、クラス名で例外の具体的な状況が表したいというのが大きいと思う。

でも、そういうのはフィールドに持たせれば十分な場合も多いので、あまり例外クラスは増やすべきではない。

ということで、これはむしろ、「他の例外クラスを継承しただけの例外クラスを作らない」とするのがいいんじゃないだろうか?

という点に不同意でしたので、その理由を詳しく書いてみます。

まず、

中身がない例外クラスを作る目的としては、クラス名で例外の具体的な状況が表したいというのが大きいと思う。

とあります。確かにその面は大きいですが、それと同時にエラーなどの種類や状況によって処理を変えたいという場合がある(そうなる可能性がある)という事があると思っています。

そうした場合、フィールドに持たせた場合は新たに例外クラスを作成した場合とでコードは以下のような感じになると思います。

// フィールドに持たせた場合
try {
  ... ;
}
catch ( FooException ex ) {
  switch ( ex.Reason ) {
  case Hoge:
    ... ;
    break;

  case Fuga:
    ... ;
    break;
  }
}
// 例外クラスを作成した場合
try {
    ... ;
}
catch ( HogeException ex ) {
  ... ;
}
catch ( FugaException ex ) {
  ... ;
}

私としては、例外処理の仕組みを考えて後者の例外クラスを作成した場合の方がより「らしい」と考えたので前者のフィールドの持たせるのは不同意としました。

.NET Framework の標準の例外で言えば、 System.IO.IOException やそれを継承したクラスなどはだいたいこんな感じで作られていると思います。このやり方が妥当かどうかは置いておいて、.NET の世界ではこういうのが流儀なんだと解釈しています。

ただし、杓子定規にエラーの種類全てに異なる例外クラスを作成するのはナンセンスで、エラーなどの種類によって処理が分岐する場合は必須ではあるのですが、別に処理を分岐させる事が無い場合は必ずしも作る必要な無いとも思っています。

例えば、標準の例外で System.Net.Sockets.SocketException はプロパティで ErrorCode というのがあってエラーの詳細はこちらで取得するようになっています*1

という訳で、「エラーなどの種類によって処理を分岐させる場合、種類に対応した例外クラスを作成するべき」なので、先の意見には不同意と考えています。

ちなみに今確認したら、以前仕事で C# を使って物を作った時は 5.5k 行で例外を90個近く作っていましたわ。無駄に作りすぎていてメンテが大変で良くなかったかも…。

*1:ただ、これは Windows のエラーコードの仕組みがそうだからってのもあるのかも…