C# は本当に便利で、実行速度を気にしなくて良い場合は、ホイホイとプログラムを書き進める事が出来ます。その反面、オブジェクト取得で null が返ってきたときなどは、やはり正当性判定を行う事になります。

さて、私が C# でプログラムを作っているときに、こんな事例に出会いました。これは編集領域で左クリックした際の処理の一部です。

var layers = mcLayer.GetSelectedLayers();
var rsc = layers[0];
Point pos = GetCharaCursorPos();
mcLayer.GetSelectedLayers() は、mcLayer オブジェクトから現在選択されているレイヤーオブジェクトを全て取得して返却する処理です。左クリックするという事で、必ずレイヤーは選択されているはずなので、問題は無い…はずでしたが、ある操作をする事で、この場所で例外が発生しました。

最初に最悪な対処方法を提示します。それは…

var layers = mcLayer.GetSelectedLayers();
if (layers == null || layers.Count <= 0) return; //**
var rsc = layers[0];
Point pos = GetCharaCursorPos();

これで例外は絶対に出なくなります。私はこの判定を安全装置と呼んでいます。が、本当にこれで良いのでしょうか。本当の問題は選択されているはずの場面で、選択レイヤーが返却されてこない事です。この根本問題を解決せず、例外が発生する問題解決のみを行ってしまうのは、例えば、体中が痛いので鎮痛剤を飲むのに似ています。その場は良いですが、薬が切れればまた痛みます。この GetSelectedLayers() を使用する全ての場所で、痛み止めという判定処理を必要としてしまいます。このままプログラムを積み重ねていけば、いつかは自分の把握範囲を超えて異常動作が顕著化していく事でしょう。最後は手が付けられなくなるかもしれません。

ということで、この場合は選択レイヤーが返ってこない問題を確認した上で、例外防止を外すべきです。ですが、プログラマも人間ですから、また再びやらかす事はあり得ます。その場合に必要なのはユーザーの不利益を最小限にする事です。先の場当たり的な例外防止ではありますが、私はリリース時には付与した方が良いという考え方です。※1 ただ、開発中は例外が起きて欲しいので、このような判定は不要です。ビルドの種別によって、ソースの動作を変えたい。それを可能とするのがプリプロセッサです。

var layers = mcLayer.GetSelectedLayers();
#if !DEBUG
if (layers == null || layers.Count <= 0) return; //**
#endif
var rsc = layers[0];
Point pos = GetCharaCursorPos();

この記述は、デバッグビルドの時はこの安全装置を外す動作となります。ログ出力などは逆にデバッグビルド時だけにビルドして欲しいので #if DEBUG と書きます。! は判定を逆にする指定ですから、このような動作になります(って C# 知ってれば当たり前すぎますな…)。

このようなプリプロセッサは他にもたくさんあります。今回紹介したのは、条件付きコンパイルという手法でかなり当たり前に使われている技術ですが、初めての人には分からない事でもありますので記事にしてみました。もっと詳細な事を知りたければこちらを見ると良いと思います。

※1 場当たり的な例外防止
オプションメニューに「デバッグに貢献する」チェックを用意して、これを意図的にチェックした人には、例外が発生するようにしても面白いかと思います。まあ、市販ソフトでは許されないとは思いますので、その場合は例外補足してダイアログ表示とログ出力までやれば凄いですが、そこまで分かってるのなら、バグ直しとけよとも思いますしバグは想定外だからバグだとも言えるので、やっばりコレは永遠のテーマだと思います