Err.Raiseステートメント
C++やJava言語のようにtry-catchによる例外処理が必須な言語と比べるとVBAにはそこまで厳密な例外処理はまず要求されることはありません。
その理由で一番大きいのは、VBAはC++やJavaのように「絶対に異常終了してはいけない」とか「24時間常時稼働」などのような厳しい条件を付きつけられることがないことが挙げられます。
ちなみに、例外処理とは、ある関数内でなんらかの実行時エラーが発生した場合に、関数の呼び元でエラーを補足してもらい異常終了しないようにするための処理を言います。
VBAではC++やJavaのような厳しい条件を要求されることはほとんどないと思いますが、それでもある程度の性能を要求されることはあるでしょう。
そのような場合に、On Error Goto で「エラー発生しました。はい、異常終了で終わります」とするのではなく、エラーを事前に検知して安全に処理を継続させるために、疑似的に例外処理を行うことが可能です。
なお一般的には、例外が発生すると以降の処理は継続させずに終了させることが多いです。
VBAでは、関数内で実行時エラーとみなされる処理の個所でErr.Eraseステートメントを使うことで疑似的に例外を発生させ、呼び出し元の関数のOn Error GoToステートメントでエラーを補足することが出来ます。
構文
Err.Raise(Number As Long, [Source], [Description], [HelpFile], [HelpContext])
Err | Errオブジェクトを指定します。 |
Number | 0から65535の範囲でエラー番号を指定します。 |
Source省略可 | エラーの発生原因のアプリケーションやオブジェクトなどを文字列で指定します。 |
Description省略可 | エラーメッセージの文字列を指定します。省略した場合は引数Numberに紐付くエラーメッセージが利用されます。 |
HelpFile省略可 | ヘルプファイルの絶対パスを指定します。 |
HelpContext省略可 | ヘルプファイルのトピックのコンテキスト番号を指定します。 |
引数は多いですが、実際に使うときは引数Numberだけを指定することが多いと思います。
サンプルコード
以下のコードは2つの関数から成り立っています。
1つ目のGetAddress関数は引数がDate型でなければ実行時エラーを発生させますが、Date型の場合は年月日表記で日付を表示します。
2つ目のOutputDate関数はGetAddress関数を呼び出す関数で、Date型とString型の2つの引数を使ってGetAddress関数をコールします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Sub GetAddress(dt) If VarType(dt) <> vbDate Then Call Err.Raise(50000, "GetAddress", "Date型の変数ではありません") End If Debug.Print Format(dt, "yyyy年mm月dd日") End Sub Sub OutputDate() On Error GoTo error_label Dim dt As Date Dim s As String dt = "2018/11/19" s = "abcde" Call GetAddress(dt) '// 2018年11月19日 Call GetAddress(s) '// 50000 Date型の変数ではありません Exit Sub error_label: Debug.Print Err.Number & " " & Err.Description End Sub |
実行結果
2018年11月19日
50000 Date型の変数ではありません
Err.Raiseを使う用途やメリット
通常はErr.Raiseを使わずに、If文でデータに問題がないかを確認して、問題があれば以降の処理をしない、というロジックを書くことが多いと思います。
では、Err.Raiseを使った場合に利点があるのか、また、用途はあるのか、というと、一応あります。
1つは、関数の引数にエラー用の引数を用意しなくていい、という点があります。
もう1つは、呼び出し元でエラーハンドリング(上記サンプルのerror_labelラベル)の前と後で、正常系の処理と異常系の処理とで完全に分離させることが出来ます。
シート操作などの処理であれば異常系のことを考える必要はあまりないですが、VBAで通信プログラムなどをコーディングした場合にFTPやTCPでの通信エラーや、ファイル操作での書き込み失敗などの外部要因によるエラーが発生するような場合は、多くの場合異常系の判定を入れることになりますが、そういう場合にはErr.Raiseで疑似的な例外として扱って、以降の処理が継続できるようなロジックにした方がいい場合があります。
Excel内に閉じたVBA処理であればあまり必要性は感じませんが、Excelの外と処理するような場合にはErr.Raiseステートメントの利用を検討してもいいかもしれません。