- 締切済み
DictionaryとRedim
Windows XP & Visual studio2005を使用しています。 以下のようなコードを書きました。 Sub Main() Dim dic1 As New Dictionary(Of Integer, Integer()) Dim dic2 As New Dictionary(Of Integer, Integer()) Dim arr1(3) As Integer Dim arr2(3) As Integer arr1(0) = 0 arr1(1) = 1 arr1(2) = 2 arr1(3) = 3 dic1.Add(0, arr1) arr1(0) = 100 arr1(1) = 101 arr1(2) = 102 arr1(3) = 103 dic1.Add(100, arr1) arr2(0) = 0 arr2(1) = 1 arr2(2) = 2 arr2(3) = 3 dic2.Add(0, arr2) ReDim arr2(3) arr2(0) = 100 arr2(1) = 101 arr2(2) = 102 arr2(3) = 103 dic2.Add(100, arr2) '*ここで止めてdic1とdic2の内容をみる dic1 = Nothing dic2 = Nothing End Sub コメントの位置で止めて、dic1とdic2の内容を見ると dic1の方は、keyの値にかかわらず、100~103が入っていますが dic2の方は、それぞれ0~3と100~103が入っています。 どうしてこのような違いが出てくるのでしょうか?
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- うぃず(@Wizard_Zero)
- ベストアンサー率69% (344/495)
非常に興味深い質問ですね。 コードだけ見ると、dic2もdic1のように先の代入が置き換えられてしまいそうですが・・・。 #1 さんのおっしゃるとおり、配列はすべて参照型として扱われます。すなわち、 > dic1.Add(0, arr1) ここでは、arr1への参照(ポインタ)がコレクションに格納されることになります。次の > dic1.Add(100, arr1) でも、同じ参照が格納されるので、 dic1(0) = dic1(100) となり、配列の内容は常に一致します。 問題はdic2のケースですね。 結果から推測すると、配列の内容が異なるということは、「コレクションに格納された参照(ポインタ)が異なる」ということを示しています。 ということは、arr2 のポインタが ReDim の前後で変わったことになります。 そこで、次のようにしてReDim前後でarr2のポインタを取得して確認してみました。 Dim gch As System.Runtime.InteropServices.GCHandle gch = System.Runtime.InteropServices.GCHandle.Alloc(arr2, Runtime.InteropServices.GCHandleType.Pinned) Console.WriteLine("ReDim前 = " & gch.AddrOfPinnedObject().ToInt32()) gch.Free() ReDim arr2(3) gch = System.Runtime.InteropServices.GCHandle.Alloc(arr2, Runtime.InteropServices.GCHandleType.Pinned) Console.WriteLine("ReDim後 = " & gch.AddrOfPinnedObject().ToInt32()) gch.Free() -- 出力結果 -- ReDim前 = 20934232 ReDim後 = 20976944 ReDimの前後でポインタが変わっています。 さらに、同じ手法で、dic1(0), dic1(100), dic2(0), dic2(100)のポインタを取得してみました。 dic1(0) = 20926012 dic1(100) = 20926012 dic2(0) = 20926040 dic2(100) = 20968752 このように、dic1(0) と dic1(100) は一致、つまり同じ参照 dic2(0) と dic(100) は不一致、つまり異なる参照 となっています。 このことから、ReDimを行うと、配列内のメモリを再割り当てするのではなく「配列の変数自体を作り直す」のだと思います。 つまり次の2つのコードはarr2に新しいポインタを与える意味で同等なのではないかと思います。 ReDim arr2(3) arr2 = New Integer() {0, 0, 0, 0} クラスで例えれば「ReDimは新しいインスタンスを作成するのと同義」となりますから、ReDim前後の配列は互いに独立した値を格納する、ということになるのだと思います。 ※回答や検証方法に間違いがあればご指摘くださいませ。
- oboroxx
- ベストアンサー率40% (317/792)
恐らくですみませんが、こういう事だと思われます。 まず、配列は参照型です。 でDictionaryのvalueは配列のアドレスを覚えていると思います。 つまりコピーしたものを内部に保有していないと。 で、arr1の配列は中の値だけが変化しているだけなので、keyが0でも100でもかわらないのです。 しかし、arr2の配列は途中でRedimしています。 これはMSDN Libraryを見ると、領域を再割り当てすると書いてあります。 つまりReDimの前後でarr2の配列は別領域を指しているのです。 で、Dictionaryはkeyが0の時と100の時で別の場所を指しているので、別々の値を保持していると思われます。