VBA – 型が一致しません(実行時エラー13)
In this Article
VBA タイプミスマッチエラー
タイプミスマッチ(型の不一致)とは?
VBAのコードを実行すると、しばしば「型が一致しません」と表示されるエラーが発生することがあります。 このエラーは、コードの実行を完全に停止させ、メッセージボックスによってこのエラーを解決する必要があることを知らせます。
ユーザーに配布する前にコードを完全にテストしていない場合、このエラーメッセージがユーザーに表示され、Excelアプリケーションの信頼性が大きく損なわれてしまうことに注意してください。 残念ながら、ユーザーはアプリケーションに対して非常に独特なことをすることが多く、開発者としては考えもしなかったようなことをすることがよくあります。
Dimステートメントで定義した変数が、ある特定の型(例えば、整数、日付)であり、コードがその変数に許容できない値を代入しようとした場合に型の不一致が発生します。(例えば、この例のように整数型変数に文字列を代入した場合。)
以下はその例です。
「デバッグ」をクリックすると、問題の行が黄色でハイライト表示されます。 これは重大なエラーであり、これ以上コードを実行することはできないため、エラーポップアップには続行するオプションがありません。 この場合、Dimステートメントを、変数に代入する値と連動する変数型に変更することで解決します。このコードは、変数の型を’String’に変更すれば動作します。また、変数名も同様に変更した方が良いでしょう。
しかし、変数の型を変更すると、プロジェクトをリセットする必要があり、コードをもう一度最初から実行しなければならなくなるため、長いプロシージャが含まれている場合は非常に面倒です。
ワークシートの計算が原因のミスマッチエラー
上の例は、ミスマッチエラーがどのように発生するかを示す非常に単純なもので、この場合、簡単に改善できます。
しかし、ミスマッチエラーの原因は、通常これよりもはるかに深いところに潜んでおり、コードをデバッグしようとしているときには、明白ではあるとは限りません。
例として、ワークシートのある位置の値をピックアップするコードを書き、そのコードがワークブック内の他のセル(この例ではB1)に依存する計算を含んでいるとします。 ワークシートは次のようなもので、文字列の中の特定の文字を見つけるための数式が書かれています。
ユーザーから見ると、セル A1 は自由形式で、好きな値を入力することができます。 しかし、数式は文字Bの出現箇所を探しており、この場合は見つからなかったので、セルB1にはエラー値が表示されています。 以下のテストコードは、セル A1 に間違った値が入力されたため、ミスマッチエラーを発生させます。
Sub TestMismatch()
Dim MyNumber As Integer
MyNumber = Sheets("Sheet1").Range("B1").Value
End Sub
セル B1 の値は、ユーザーがセル A1 に入力したテキストが期待されたものと一致せず、文字 B を含んでいないためエラーになりました。
このコードでは、整数が入力されることを期待して定義された変数 MyNumber に文字列を代入しようとしたため、ミスマッチエラーが発生しています。
これは、コードを注意深くチェックしても答えが出ない例の一つです。また、なぜこのようなことが起こるのかを知るためには、その値がどこから来るのかをワークシート上で確認する必要があります。
問題は実際にワークシート上にあり、B1の数式を変更して、エラー値を処理する必要があります。IFERROR」式を使用して、検索文字が見つからない場合、デフォルト値として0を提供することでこれを行うことができます。
次に、0 の値をチェックし、セル A1 の値が無効であるという警告メッセージをユーザーに表示するコードを組み入れることができます。
Sub TestMismatch()
Dim MyNumber As Integer
MyNumber = Sheets("Sheet1").Range("B1").Text
If MyNumber = 0 Then
MsgBox "セルA1の値が無効です", vbCritical
Exit Sub
End If
End Sub
また、ユーザーが好き勝手なことをしてワークシートエラーを発生させないように、スプレッドシートで「データの入力規則」(リボンのデータタブのデータツールグループ)を使用し、ワークシートエラーを引き起こさない値だけを入力させることもできます。
他にも、ワークシートの変更イベントに基づいてVBAコードを書き、入力されたものをチェックすることができます。
また、ワークシートをロックしてパスワードで保護し、無効なデータを入力できないようにすることも可能です。
入力されたセル値によるミスマッチエラー
ミスマッチエラーは、ワークシートから正常な値を取り込む (非エラー) ことにより発生しますが、ユーザーが予期しない値を入力した場合 (たとえば、数値を期待していたのにテキストを入力した場合) にも発生します。 例えば、数値の範囲内に行を挿入して、その数値について何か説明するメモをセルに書き込むような場合です。結局のところ、ユーザーはあなたのコードがどのように動作するのか知らないし、メモを入力することによって全体を混乱させただけなのです。
以下のコード例では、整数値で定義されたMyNumberという単純な配列を作成しています。
このコードは、A1 から A7 までのセル範囲を繰り返し、セルの値を配列に代入し、変数Counを使用して各値のインデックスを作成します。
コードがテキスト値に到達すると、ミスマッチエラーが発生し、すべてが停止してしまいます。
エラーポップアップの「デバッグ」をクリックすると、問題のあるコード行が黄色でハイライト表示されます。コード内の変数「Coun」のインスタンスにカーソルを置くと、コードが失敗した「Coun」の値(この場合は5)が表示されます。 ワークシートを見ると、5つ下のセルにテキスト値があり、これがコードの失敗の原因になっていることがわかります。
配列にセルの値を追加する前に、最初に数値をチェックする条件を追加することで、コードを変更することができます。
Sub TestMismatch()
Dim MyNumber(10) As Integer, Coun As Integer
Coun = 1
Do
If Coun = 11 Then Exit Do
If IsNumeric(Sheets("sheet1").Cells(Coun, 1).Value) Then
MyNumber(Coun) = Sheets("sheet1").Cells(Coun, 1).Value
Else
MyNumber(Coun) = 0
End If
Coun = Coun + 1
Loop
End SUb
このコードでは、「IsNumeric」関数を使って、値が実際に数字であるかどうかをテストし、数字であれば配列にそれを入力しています。数値でない場合は、0を入力します。
これにより、配列のインデックスがスプレッドシートのセル行番号と一致するようになります。
また、元のエラー値と場所の詳細を「エラー」ワークシートにコピーするコードを追加して、コードを実行したときにユーザーが自分の間違いを確認できるようにすることもできます。
数値テストでは、配列に値を代入するコードだけでなく、セルの完全なコードも使用します。 同じコードを繰り返さないために、変数に代入するべきだと主張することもできますが、問題は、変数をバリアント型として定義する必要があることです。
また、ワークシートのデータの入力規則やワークシートのパスワード保護も有効です。 これにより、ユーザーが行を挿入し、予期しないデータを入力することを防ぐことができます。
パラメータを使用して関数やサブルーチンを呼び出すと発生するミスマッチエラー
関数が呼び出された場合、通常は関数で定義されているデータ型を使って関数にパラメータを渡します。関数は、VBAですでに定義されている関数かもしれませんし、自分で作成したユーザー定義関数かもしれません。また、サブルーチンでもパラメータを必要とする場合があります。
パラメータを関数に渡す方法の規則に従わない場合、ミスマッチエラーが発生します。
Sub CallFunction()
Dim Ret As Integer
Ret = MyFunction(3, "test")
End Sub
Function MyFunction(N As Integer, T As String) As String
MyFunction = T
End Function
ここでミスマッチエラーが発生する可能性はいくつかあります。
戻り値変数Retは整数として定義されていますが、関数は文字列を返しています。このコードを実行するとすぐに失敗します。なぜなら、この関数は文字列を返しており、これを整数型変数に入れることはできないからです。 興味深いことに、このコードに対してDebugを実行しても、このエラーは検出されません。
この関数に渡される最初のパラメータの3を引用符で囲むと、文字列として解釈されるため、関数の最初のパラメータの定義(integer)と一致しなくなります。
また、関数呼び出しの2番目のパラメータを数値にすると、文字列の2番目のパラメータが文字列として定義されているため、ミスマッチが発生して失敗します。
VBAの変換関数を間違って使用した場合のミスマッチエラー
VBAには、値をさまざまなデータ型に変換するために利用できる変換関数が多数用意されています。例えば、CIntは、数値を含む文字列を整数値に変換する関数です。
変換する文字列に数値以外の文字が含まれていると、文字列の最初の部分が数字であっても、ミスマッチエラーが発生します。(例:「123abc」)
ミスマッチエラーを防ぐための一般的な対策
上記の例では、コード内で起こりうるミスマッチエラーに対処する方法をいくつか紹介しましたが、 他にもいくつかの方法があります。
変数をVariant型で定義する
バリアント型は、VBAのデフォルトの変数型です。変数にDimステートメントを使用せず、単にコードで使用し始めると、自動的にバリアント型が与えられます。 バリアント型変数は、整数、長整数、倍精度数、ブーリアン、テキストなど、どんなタイプのデータでも受け入れることができます。これは素晴らしいアイデアのように聞こえますが、なぜ誰もがすべての変数をバリアント型に設定しないのか不思議に思うでしょう。
それは、バリアント型にはいくつかの欠点があるからです。まず、他のデータ型に比べてはるかに多くのメモリを消費します。 非常に大きな配列をバリアントとして定義した場合、VBAコードの実行時に大量のメモリを消費し、パフォーマンスの問題を引き起こしやすくなります。
第二に、特定のデータ型を使用する場合よりも、一般的にパフォーマンスが遅くなります。 例えば、浮動小数点数を使って複雑な計算をする場合、倍精度数ではなくバリアントとして数値を格納すると、計算がかなり遅くなります。
バリアント型を使うことは、絶対的な必要性がない限り、ずさんなプログラミングとみなされます。
OnErrorコマンドでエラーを処理する
OnErrorコマンドは、エラートラッピングに対処するためにコードに含めることができ、エラーが発生した場合、ユーザーは標準のVBAエラーポップアップの代わりに意味のあるメッセージを見ることができます。
Sub ErrorTrap()
Dim MyNumber As Integer
On Error GoTo Err_Handler
MyNumber = "test"
Err_Handler:
MsgBox "エラー " & Err.Description & " が発生しました"
End Sub
これにより、エラーによってコードのスムーズな実行が妨げられるのを効果的に防ぎ、ユーザーがエラー状況からきれいに回復できるようになります。
Err_Handler ルーチンは、エラーに関する詳細な情報と、エラーに関する連絡先を表示することができます。
プログラミングの観点からは、エラー処理ルーチンを使用している場合、エラーが発生しているコードの行を見つけることは非常に困難です。F8 を使ってコードをステップ実行している場合、問題のある行が実行されるとすぐにエラー処理ルーチンにジャンプしてしまい、どこでエラーが発生しているのかを確認することができません。
これを回避する方法は、True または False (Boolean) のグローバル定数を設定し、これを使用して ‘If’ 文でエラー処理ルーチンをオンまたはオフにすることです。 エラーをテストしたいときは、グローバル定数をFalseに設定するだけで、エラーハンドラは動作しなくなります。
Global Const ErrHandling = False
Sub ErrorTrap()
Dim MyNumber As Integer
If ErrHandling = True Then On Error GoTo Err_Handler
MyNumber = "test"
Err_Handler:
MsgBox "エラー " & Err.Description & " が発生しました"
End Sub
この問題の1つは、ユーザーがエラーから回復することができますが、サブルーチン内の残りのコードは実行されないということで、アプリケーションの後半に大きな影響を与える可能性があることです。
先ほどのセル範囲をループする例では、セル A5 に到達してミスマッチエラーが発生しました。 ユーザはエラーに関する情報を提供するメッセージボックスを見ることができますが、そのセル以降の範囲は何も処理されません。
OnErrorコマンドでエラーを抑制する
On Error Resume Nextコマンドを使用するとエラーが発生しても実行が継続されますが、それ以降のエラーが表示されなくなるため、非常に危険です。 これは基本的に、コードの実行中にエラーが発生した場合、エラー行を実行せずに次の利用可能な行に移動し、通常通り実行されることを意味します。
これは、潜在的なエラーの状況を解決するかもしれませんが、コード内の将来のすべてのエラーに影響を与えることに変わりはありません。そうすると、自分のコードにはバグがないと思っていても、実はそうではなく、コードの一部が自分が思うような動きをしていないことになります。
例えば、Killコマンドでファイルを削除する場合のように、このコマンドを使う必要がある場合もあります。(ファイルが存在しない場合はエラーになります。)ただしこの場合、エラーが発生する可能性がある場所の直後で、エラートラッピングを有効に戻す必要があります。
On Error Goto 0
先ほどのセルの範囲をループする例では、On Error Resume Nextを使用すると、ループは継続できますが、エラーが発生したセルは配列に転送されず、その特定のインデックスの配列要素にはnull値が保持されることになります。
宣言と一致するデータ型に変換する
VBA関数を使用して、入力されるデータのデータ型を変更し、受信する変数のデータ型と一致させることができます。
この機能は、関数にパラメータを渡すときに使用します。 例えば、文字列変数に格納されている数値を関数に整数として渡す場合、CInt または CLng を使います。
このような変換関数はいくつもありますが、ここでは主なものを紹介します。
CInt – 数値(+/- 32,768まで)を持つ文字列を整数型の値に変換します。この場合、小数点以下は切り捨てられることに注意してください。
CLng – 大きな数値の文字列を長整数型に変換します。 小数点以下は切り捨てられます。
CDbl – 浮動小数点数を持つ文字列を倍精度の数値に変換します。 小数点以下も含まれます。
CDate – 日付を保持する文字列を日付変数に変換します。日付がどのように解釈されるかは、Windowsのコントロールパネルとロケールの設定に部分的に依存します。
CStr – 数値または日付の値を文字列に変換します。 文字列から数値または日付に変換する場合、文字列には数値または日付以外のものを含んではいけません。それ以外の文字が含まれる場合は、ミスマッチエラーが発生します。以下は、ミスマッチエラーが発生する例です。
Sub Test()
MsgBox CInt("123abc")
End Sub
コード内の変数をテストする
特定の型の変数に代入する前に、その変数がどのようなデータ型であるかをテストすることができます。
例えば、VBAのIsNumeric関数を使って、文字列が数値かどうかを確認することができます。
MsgBox IsNumeric("123test")
このコードはFalseを返します。なぜなら、文字列は数字で始まっていますが、テキストも含まれているので、テストに失敗するからです。
MsgBox IsNumeric("123")
このコードは、すべて数字であるため、Trueを返します。
VBAには、さまざまなデータ型をテストする関数がありますが、主なものは次のとおりです。
IsNumeric – 式が数値であるかどうかをテストします。
IsDate – 式が日付であるかどうかをテストします。
IsNull – 式が NULL かどうかを調べます。null 値は、バリアントオブジェクトにのみ入れることができ、そうでない場合は Invalid Use of Null というエラーが発生します。メッセージボックスは、質問するためにそれを使用している場合、null 値を返しますので、戻り値の変数はバリアントでなければなりません。null 値を使った計算は常に null という結果を返すということも覚えておくと良いでしょう。
IsArray – 式が配列を表しているかどうかをテストします。
IsEmpty – 式が空であるかどうかをテストします。 空は、NULLと同じではないことに注意してください。変数が最初に定義されたときは空ですが、それはヌル値ではありません。
意外なことに、IsText や IsString を表す関数はありません。
オブジェクトとミスマッチエラー
範囲やシートのようなオブジェクトを使用している場合、実行時ではなくコンパイル時にミスマッチエラーが発生し、コードがうまくいかないという警告を与えます。
Sub TestRange()
Dim MyRange As Range, I As Long
Set MyRange = Range("A1:A2")
I = 10
x = UseMyRange(I)
End Sub
Function UseMyRange(R As Range)
End Function
このコードでは、UseMyRangeという関数と、Rangeオブジェクトとして渡されるパラメータがあります。しかし、渡されたパラメータは長整数型であり、データ型と一致していません。 VBAのコードを実行すると、すぐにコンパイルされ、このエラーメッセージが表示されます。
問題のあるパラメータは、青色の背景でハイライト表示されます。 一般的に、VBAのコードでオブジェクトを使用してミスをした場合、型の不一致のメッセージではなく、このエラーメッセージが表示されます。