例外

概要

プログラムがある処理を実行している途中でなんらかの異常が発生した場合に現在の処理を中断して別の処理を行うこと。その際に発生した異常のことを例外と呼ぶ。
何を持って「異常」とするかは様々であるが、次のようなものが挙げられる。
  1. ハードウェアの故障
  2. オペレーティングシステム等、システムの設定ミス
  3. ライブラリの欠損
  4. 割り当てられていない記憶領域へのアクセス
  5. 許されない演算(零での除算や実数演算で解が虚数になる演算など)
上位ほど重大で正常復帰させるのは難しい。3以上はDBの実装しだいで回避できるはず。

アンセーフコードで使うアンマネージドメモリはVirtualAllocで確保するため、確保できなかったときのエラー処理はわかりやすい。
問題はマネージドメモリの例外だ。これが発生する可能性はあらゆるところである。例えば

  • 作業用のコレクションクラス
  • DynamicMethod
  • StringBuilder
...
どれも便利で必須だがコード内のあらゆる場所に出現する。
これらのエラーが発生すべき場所を特定し、然るべき処理法を確立しなければならない。

foreachを使わずforを使う

foreachはIEnumeratorを継承したクラス(参照)型オブジェクトを使う。
マネージドヒープから確保するためOutOfMemoryExceptionを発生させる可能性がある。
forでループカウンタを使ったほうがよいかと。

セーフコードをアンセーフコードに置き換え

デバッグコード以外、全てアンセーフコードを駆使してOutOfMemoryの可能性を消す。
アンマネージドメモリ確保失敗する位置を限定させ、適切な復帰処理を入れる。
デバッグコードはセーフコードを使うことが多い。
これも可能であれば例外を発生させたくない。回避策としてエラーの対処が難しい、複雑、遅いと思われるところは前もって必要なメモリ量、要素数を計測しておきその後の処理でOutOfMemoryExceptionが理論上発生しない状態を作ってから処理する。
例えはList.Addは追加すべき要素数がわかっているならできるだけCapacityを増やすのに成功したら処理する。
内部で例外オブジェクトを送信するなら例外オブジェクトはあらかじめnewで作っておくなど。

INSERTの索引の追加時に重複エラーがあった場合例外はthrowせずにグローバル変数にエラーが有ったという情報のみを格納して重複追加する。
INSERT処理が終わったらそのフラグを見て重複エラーがあれば追加した行を全て削除して解放する。
重複エラーがない率が高ければ高速。

プログラム側でthrow new ...Exceptionする場合、このExceptionオブジェクト自体がOutOfMemoryすることがある。
それを考慮して例外を補足するが例外オブジェクトはあらかじめnewしておき使いまわすのもよい。

UPDATE連鎖,DELETE連鎖のための準備データは現在セーフコードを使っているためOutOfMemoryExceptionが発生する。成功すれば既に確保したアンセーフコードに対してのみ操作するから最後まで成功するはず。
しかしこれも処理高速化、例外の可能性を消すためにアンセーフコードにする。
UPDATE連鎖はアンセーフコード、マネージドメモリ共に途中でOutOfMemoryExceptionが発生する。
最終更新:2008年12月27日 14:20
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。