ここから本文です

[Excel_VBA]Dictionaryオブジェクトの変数の型について

yasukiyonetさん

2010/4/1122:59:32

[Excel_VBA]Dictionaryオブジェクトの変数の型について

-----------
Dictionaryオブジェクトの資料を見直していてふと、「項目(Item)にオブジェクト変数を格納できる」のではないかと思いました。んで試したところできました。

'--------------------
Sub sample1()
Dim Dic As Object
Dim myDic As Variant

Set Dic = CreateObject("Scripting.Dictionary")
'''範囲A1~A10をキーAの項目として格納
Dic.Item("A") = Sheet1.Range("A1:A10")

'''格納したアイテムをコレクションとしてループ
For Each myDic In Dic.Item("A")
Debug.Print myDic
Next

End Sub
'--------------------

<質問1>
ただ、「Dim myDic As Variant」は"箱"として大きすぎるのでピッタリの"箱"があるのだろうと思います。しかし、見つけることができません。基本的なことかもしれませんが、ご教示よろしくお願い致します。

'''''''''''''''

<質問2>
参照設定:Microsoft Scripting Runtimeにチェックをいれて書き直せば、<質問1>を自力で解くことができると思い以下を試しました。んが疑問が増えました。

'--------------------
Sub sample2()
Dim Dic As Scripting.Dictionary
Dim myDic

Dic.Item("A") = Sheet1.Range("A1:A10")

For Each myDic In Dic.Item("A")
Debug.Print myDic
Next

End Sub
'--------------------

上のコードは「Dic.Item("A") = Sheet1.Range("A1:A10")」でerrorになります。

------------------
実行時エラー'91':

オブジェクト変数またはWithブロック変数が設定されていません。
------------------

思い当たる回避方法を試しましたが、何れもエラーを回避することができません。どこをどう修正すればいいのでしょうか?解り難い質問かもしれませんが、ご教示よろしくお願いいたします。

補足みなさま回答ありがとうございます。いままで配列には数値か文字列しか格納したことがなかったので、そんな誤りをしていると思いませんでした。いただいた回答をみて「オブジェクトとして、格納するならセットする必要があるよな」と思った次第。Rangeの型でループできない時点で気付きそうなものだけど…気付けませんでした。いい勉強になりました。しばらく質問は開けておくので予めご了承くださいませ。

閲覧数:
8,377
回答数:
2
お礼:
50枚

違反報告

ベストアンサーに選ばれた回答

hotosysさん

編集あり2010/4/1206:56:15

独学なので間違っているかもしれませんが・・・

<質問1>
>Dic.Item("A") = Sheet1.Range("A1:A10")
は、Rangeのデフォルトのプロパティの.Valueを省略したもので、
Dic.Item("A") = Sheet1.Range("A1:A10").Value
としたのと同等だと思います。
なので、Dic.Item("A")にはRangeのValueが入っているので、Variant型の2次元配列が入っていると思います。
>Dic.Item("A") = Sheet1.Range("A1:A10")
の後に
MsgBox TypeName(Dic.Item("A"))
MsgBox UBound(Dic.Item("A"), 1)
MsgBox UBound(Dic.Item("A"), 2)
MsgBox Dic.Item("A")(1, 1) 'A1の値
とすればわかると思います。
デバッグ中にDicやDic.Item("A")をウォッチしてみると何が入っているかわかると思います。
なので
Dim myDic As String
でもいいと思いますが、
For Each myDic In ...
でmyDicはVariantかオブジェクトしか指定できないのでVariantを指定するしかないと思います。

例えば、Dic.Item("A")にRangeオブジェクトを格納するなら、myDicはRangeオブジェクトを指定するのがいいのかもしれません。
Sub sample1()
Dim Dic As Object
Dim myDic As Range
Set Dic = CreateObject("Scripting.Dictionary")
Set Dic.Item("A") = Sheet1.Range("A1:A10") 'Rangeオブジェクトを格納(オブジェクトの場合はSetが必要)
For Each myDic In Dic.Item("A")
Debug.Print myDic.Address, myDic.Value
Next
Debug.Print Dic.Item("A").Range("A1")
Set Dic = Nothing
End Sub


<質問2>
Dim Dic As Scripting.Dictionary
Set Dic = New Scripting.Dictionary
で設定する方法と
Dim Dic As New Scripting.Dictionary
と、Dimする時点でNewする方法があるようです。
ただ、質問1でもそうですが、CreateObjectしたり、Newで参照を作ったオブジェクトは、最後に
Set Dic = Nothing
として明示的に開放した方がいいようです(確かではないのですが、やってて悪い事はないようです)。

質問した人からのコメント

2010/4/15 22:42:02

降参 みなさま回答ありがとうございます。

本件、常識なことなのかもしれませんが、私にとっては意外なことだったので、忘れぬよう資料にさせていただきました。

[VBA]Dictionaryオブジェクト_項目(アイテム)にオブジェクトや配列を格納する。
http://cid-f37c5f4ba95cd86e.spaces.live.com/blog/cns!F37C5F4BA95CD8...

ベストアンサー以外の回答

1〜1件/1件中

neko8nosukeさん

編集あり2010/4/1223:36:07

こんばんは。

>質問1

正確なデータ型は、Scripting.Dictionaryですが、このデータ型を使うためには参照設定が必要です。
Variant型にして置くメリットは、参照設定をしないでDictionaryを呼べる点ですね。

>質問2

それがエラーになるのは、データ型の問題でないですね。
サンプル1で、
Set Dic = CreateObject("Scripting.Dictionary")と、
インスタンスを作っている部分が抜けてます。

NEWキーワードを使用して、インスタンスの生成を行えば同じ事ができます^^/

Sub sample2()
Dim Dic As Scripting.Dictionary
Dim myDic

Set Dic = New Scripting.Dictionary ''ここです!
Dic.Item("A") = Sheet1.Range("A1:A10")

For Each myDic In Dic.Item("A")
Debug.Print myDic
Next

End Sub

<補足>
>いままで配列には数値か文字列しか格納したことがなかった
ん??

若干不安なので、確認。
myDicに入るデータ型に関係なく、インスタンスの生成は必要ですよ。
myDicのデータ型は、hotosysさんの仰るとおりセルの値からなる2次元配列です。
セルの値に入る可能性があるのは、数値・文字・エラー値などがあるので
事前に型を宣言するのは、不便です。

○hotosysさん
こんばんは。
私も同じく独学なので、知識的に不十分なのに余計な事かも知れません。

Dictionaryだけでなく、すべてのクラスでAs Newでのデータ宣言は、推奨されない書き方らしいですよ。
(私も以前、こういう掲示板で怒られました~^^;)

そういうサンプルも多いので、知識として知っておいて損はありませんが
他人に紹介する場合は、デメリットに付いても一言添えた方が親切ですね~。

データ型をすべてVariantにすれば、変数に何が入るかなんて一切気にしないで宣言できますが、使わないのと同じで
勝手にインスタンスができるのは、予期せぬ時にインスタンスができると言う事でもあるのです。

たとえば、
Sub sample3()
Dim Dic As New Scripting.Dictionary
Set Dic = Nothing
MsgBox Dic Is Nothing
End Sub

DicはNothingなのに、Is NothingはFalseを返します。
これはIsでアクセスしたのと同時に、インスタンスが作られたからなのです。
とっても不便ですね。

あわせて知りたい

みんなで作る知恵袋 悩みや疑問、なんでも気軽にきいちゃおう!

Q&Aをキーワードで検索:

Yahoo! JAPANは、回答に記載された内容の信ぴょう性、正確性を保証しておりません。
お客様自身の責任と判断で、ご利用ください。
本文はここまでです このページの先頭へ

「追加する」ボタンを押してください。

閉じる

※知恵コレクションに追加された質問や知恵ノートは選択されたID/ニックネームのMy知恵袋で確認できます。