VBAでScripting.DictionaryのExistsメソッドを使っているにもかかわらず、未登録のキーが登録されたように見えたり、Existsが予想外にTrueを返したりするケースがあります。特にWorksheetから取得したVariant型の二次元配列を扱う場合は、データ型や暗黙的な変換が影響することがあります。この記事では、DictionaryのExistsとVariant配列の関係について解説します。
DictionaryのExistsは本来キーを追加しない
Scripting.DictionaryのExistsメソッドは、指定したキーが存在するかどうかを確認するだけのメソッドです。
そのため、正常な動作であればExistsを実行しただけでキーが追加されることはありません。
If dic.Exists("ABC") Then
MsgBox "存在します"
End If
上記のコードでは、Existsの実行によってDictionaryの内容が変化することはありません。
Variant型の二次元配列で起こりやすい問題
Excelのセル範囲を配列へ読み込むと、多くの場合はVariant型の二次元配列になります。
このとき、見た目は文字列でも内部的にはEmpty、Null、Error値、またはVariant/Stringなど複数の状態が混在する可能性があります。
例えば次のようなコードでは、aaa(i,1)のデータ型によって予想外の挙動が発生することがあります。
If newDic.Exists(aaa(i,1)) Then
'処理
End If
特にセルに数式エラーや不可視文字、全角スペースなどが含まれている場合は注意が必要です。
String変数へ代入すると正常になる理由
質問のケースでは、一度String型変数へ代入すると正常に判定できています。
Dim str As String
str = aaa(i,1)
If newDic.Exists(str) Then
'処理
End If
これは代入時にVBAが明示的な型変換を行い、VariantがStringへ正規化されるためです。
つまり問題の本質は二次元配列ではなく、Variant型の中身やサブタイプにある可能性が高いと言えます。
Dictionaryの既定プロパティとの混同にも注意
Dictionaryでは既定プロパティであるItemを参照した場合、存在しないキーへのアクセスで新規キーが生成されることがあります。
value = dic("ABC")
上記のようなコードは、設定や実装によってはキー追加の原因になることがあります。
そのため、Existsの直前や直後でDictionaryのItemプロパティを参照していないかも確認してみる価値があります。
調査時に確認したいポイント
原因を切り分けるために、以下の情報を出力してみると有効です。
- TypeName(aaa(i,1))
- VarType(aaa(i,1))
- Len(aaa(i,1))
- AscやAscWによる文字コード確認
これにより、見た目は同じ文字列でも実際には異なるデータが入っているケースを発見できます。
| 確認項目 | 目的 |
|---|---|
| TypeName | 実際の型を確認 |
| VarType | Variantのサブタイプ確認 |
| Len | 余分な文字の有無確認 |
| AscW | 不可視文字の検出 |
再発防止のための実装例
実務ではDictionary検索前に明示的な型変換を行うケースが多くあります。
Dim key As String
key = Trim$(CStr(aaa(i,1)))
If newDic.Exists(key) Then
'処理
End If
DictionaryのExists自体がキーを追加することは基本的にありません。Variantの型情報や別箇所でのItem参照が影響しているケースを疑うべきです。
まとめ
VBAのDictionaryでExistsを実行しただけでキーが追加されたように見える場合、二次元配列そのものが原因というより、Variant型の内部データや暗黙的な型変換が関係している可能性が高いです。
特にExcelから取得した配列データは型が一定ではないため、一度String変数へ代入してからExistsを実行する方法は有効な対策です。また、TypeNameやVarTypeで実際のデータ型を確認することで原因究明につながるでしょう。

コメント