VBAには On Error によるエラートラップ以外にIsError関数によるエラー判定方法が存在する。
例外処理に慣れたプログラマであれば、なんということもない処理だね。
CVErrは整数値をErr型に変換してくれる。
ただし、CVErrを使った関数は戻り値の型をVariantにする必要がある。
こちらはCのAPIでよくある正常時は0を返して、異常時はエラー番号を返すような処理に似ている。
呼び出し側はIsErrorを使うことによって、エラーが起きたかどうかを判定することができる。
なんで、こんな機能が言語レベルでサポートされているんだろう?
て思ったんだけど、VBAの中で使うのではなく、Excelのユーザー定義関数としてなら、これはかなり便利。
というより、ユーザー定義関数でいちいちErr.Raiseされたらひどいことになるよね。
※ユーザー定義関数ってのはVBAで自分で作った関数をSUMのようにExcelのセルの中から呼べる機能ね。
この場合、Err型の変数を返せば、Excelがセルに"#N/A"とか"#DIV0!"とか表示してくれる。
Excel VBA リファレンス セルのエラー値
確かにExcelではどんな数値や文字列だったら、エラーだなんて言えないからね。
まあ、実際になんでVBAにIsErrorが導入されたかの経緯はわかりませんが...
こんなときに値を格納するための変数とエラーフラグ用の変数を用意するのはめんどくさいよね。
ループの中でいちいち例外処理をするのはもっと煩わしい!
というわけ(?)で、Javaの場合はプリミティブ型ではなく、Integerのようなラッパークラスを使えば、nullを返すことができる。
C#だと、Nullableにすれば、nullを返すことができる。
でも、nullでエラーを表現するってのも、あまりかっこよくないね。
Errorableみたいなラッパークラスを作って、isErrorメソッドを用意するといいかもしれない。
あとは評価すると元のエラーに該当する例外が発生するメソッドとか。
C#で書くと、こんな感じだろうか。
Java8であれば、Optionalがあるので、それを使えばいいのかもしれませんが...
"On Error" or "IsError" ?
例えば、引数が負数であればエラーとする処理は以下のようになる。Function MustBePositiveOnErr(ByVal v As Long) As Variant MustBePositiveOnErr = v If v < 0 Then Err.Raise 5 ' Invalid Procedure call or argument.' End If End Function
例外処理に慣れたプログラマであれば、なんということもない処理だね。
CVErrは整数値をErr型に変換してくれる。
ただし、CVErrを使った関数は戻り値の型をVariantにする必要がある。
Function MustBePositiveCVErr(ByVal v As Long) As Variant MustBePositiveCVErr = v If v < 0 Then MustBePositiveCVErr = CVErr(5) End If End Function
こちらはCのAPIでよくある正常時は0を返して、異常時はエラー番号を返すような処理に似ている。
呼び出し側はIsErrorを使うことによって、エラーが起きたかどうかを判定することができる。
Debug.Print IsError(MustBePositiveCVErr(1)) ' False' Debug.Print IsError(MustBePositiveCVErr(-1)) ' True'
Excelのユーザー定義関数
CVErrとIsErrorの組み合わせは戻り値でエラーを表現する方法をより一般化したものと言える。なんで、こんな機能が言語レベルでサポートされているんだろう?
て思ったんだけど、VBAの中で使うのではなく、Excelのユーザー定義関数としてなら、これはかなり便利。
というより、ユーザー定義関数でいちいちErr.Raiseされたらひどいことになるよね。
※ユーザー定義関数ってのはVBAで自分で作った関数をSUMのようにExcelのセルの中から呼べる機能ね。
この場合、Err型の変数を返せば、Excelがセルに"#N/A"とか"#DIV0!"とか表示してくれる。
Excel VBA リファレンス セルのエラー値
確かにExcelではどんな数値や文字列だったら、エラーだなんて言えないからね。
まあ、実際になんでVBAにIsErrorが導入されたかの経緯はわかりませんが...
ラッパークラス、Nullable、Errorable?
IsErrorの考え方はループの中で全件処理して、どの値が不正だったかを調べる場合に応用できそう。こんなときに値を格納するための変数とエラーフラグ用の変数を用意するのはめんどくさいよね。
ループの中でいちいち例外処理をするのはもっと煩わしい!
というわけ(?)で、Javaの場合はプリミティブ型ではなく、Integerのようなラッパークラスを使えば、nullを返すことができる。
C#だと、Nullableにすれば、nullを返すことができる。
でも、nullでエラーを表現するってのも、あまりかっこよくないね。
Errorableみたいなラッパークラスを作って、isErrorメソッドを用意するといいかもしれない。
あとは評価すると元のエラーに該当する例外が発生するメソッドとか。
C#で書くと、こんな感じだろうか。
class Errorable# ここまで書いて、気づいたんだけど、これって非同期処理の一般形式ですね。{ private T val; private Exception e; public Errorable(T val) : this(val, null) { } public Errorable(T val, Exception e) { this.val = val; this.e = e; } public T Value { get { return val; } } public Exception exception { get { return e; } } public bool IsError() { return e != null; } public T GetValue() { if (IsError()) { throw e; } return val; } }
Java8であれば、Optionalがあるので、それを使えばいいのかもしれませんが...
0 件のコメント:
コメントを投稿