1

I am trying to create a Dictionary collection of keys, where each key would have a corresponding value of class "look". The following example does not work. It gives me:
first - circle, blue
second - circle, blue

While I need:
first - square, red
second - circle, blue

Why does it not work and how can I make it work?
Thank you.

Public Class Form1

Public Class look
    Public shape As String
    Public color As String
End Class

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim myDict As New Dictionary(Of String, look)
    Dim oLook As New look
    oLook.shape = "square"
    oLook.color = "red"
    myDict.Add("first", oLook)
    oLook.shape = "circle"
    oLook.color = "blue"
    myDict.Add("second", oLook)
    For Each key In myDict.Keys
        MsgBox(key & " - " & myDict(key).shape & ", " & myDict(key).color)
    Next
End Sub
End Class
GreenBear
  • 373
  • 1
  • 6
  • 18

2 Answers2

3

Try this:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim myDict As New Dictionary(Of String, look)
    Dim oLook As New look
    oLook.shape = "square"
    oLook.color = "red"
    myDict.Add("first", oLook)
    oLook = new look ' This will create another oLook object and point olook at it.
    oLook.shape = "circle"
    oLook.color = "blue"
    myDict.Add("second", oLook)
    For Each key In myDict.Keys
        MsgBox(key & " - " & myDict(key).shape & ", " & myDict(key).color)
    Next
End Sub
JerryM
  • 910
  • 6
  • 9
  • Thanks for the help. Can anybody explain me how this works? Do I get two oLook objects? How do I destroy them after I put a value into the dictionary? My dictionary will have about a billion keys, so I need to do it economical. – GreenBear Oct 26 '15 at 19:59
  • 2
    @GreenBear oLook doesn't contains your object but a reference to the object created (by using new). So when you set it's shape and color it refers to the object referenced. When you add it to the dictionary it's also the reference that is stored. That's why "both" oLook are updated to the same value (the referenced object is still the same only it's members were mutated). If i do an analogy that's the same as giving someone's address whose house is red storing that address somewhere and then painting the house in blue and storing the (same) address ; both address refers to the same blue house – Sehnsucht Oct 26 '15 at 20:07
  • 2
    @GreenBear for the removal part ; (I simplified things here) : an object lies in memory as long as "something" holds a reference to it. As soon as there is no one keeping a reference (by setting a variable to Nothing and/or deleting the key/value pair in the dict for example) that object gets eligible to collection by the garbage collector. It's him which will effectively "free" the memory when at some point (in classic scenario we don't really control when). – Sehnsucht Oct 26 '15 at 20:13
  • 1
    If you will have `a billion keys` you should be using a database. You dont destroy them after you put them in the collection. – Ňɏssa Pøngjǣrdenlarp Oct 26 '15 at 20:18
  • Thank you, Sehnsucht. I thought that Dictionary contains objects, not references to objects. Now it all makes sense. – GreenBear Oct 26 '15 at 20:24
  • 1
    @GreenBear If by object you mean value types, then you're wrong. Change `public class look` aka. ref type to `public structure look` aka. value type and it still work. Only difference is that now your original code will work. – Bjørn-Roger Kringsjå Oct 26 '15 at 20:31
  • Thank you, Bjørn-Roger Kringsjå. I wish you would have answered my question earlier. – GreenBear Oct 26 '15 at 20:43
  • @Bjørn-Roger Kringsjå, so we can program with either class or structure. Which way is more efficient in terms of speed and memory consumption? Or there is no difference? – GreenBear Oct 26 '15 at 20:59
  • 1
    @GreenBear A potentially significant difference between value and object types involve the .Net processes of boxing and unboxing. When value types are passed to methods, they can get converted to an object and then back again. This can take additional time and memory. Generally, I would go with objects. Here some references: http://www.dotnet-tricks.com/Tutorial/csharp/HL1W121013-Understanding-Boxing-and-Unboxing-in-C, https://msdn.microsoft.com/en-us/library/yz2be5wk.aspx. – JerryM Oct 26 '15 at 21:17
  • 1
    @GreenBear Sure, but you have to know the difference. The common consensus is to use ref types over value types, but that's not always true. I advise you to study the difference between the two types. You should also research mutable vs. immutable. This is the reason why I gave you the link in the first place and not a copy & paste answer. Btw, with a billion entries you'll probably run into an out of memory exception as the length of the underlying array used in the Dictionary is set by a prime number. – Bjørn-Roger Kringsjå Oct 26 '15 at 21:18
  • 1
    I thought I had miss-read "billion", but now I see that I didn't. Since each object reference is 8 bytes, you will reach the 2GB object limit with 250 million objects. In Framework 4.5 you can exceed this limit. I don't know if you can make longer lists, or just arrays. Let us know! https://msdn.microsoft.com/en-us/library/hh285054(v=vs.110).aspx – JerryM Oct 26 '15 at 21:32
  • @JerryM AFAIK it's still ~2GB: http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,eb66b6616c6fd4ef,references – Bjørn-Roger Kringsjå Oct 26 '15 at 21:33
  • For very large Dictionary(Of TKey, TValue) objects, you can increase the maximum capacity to 2 billion elements on a 64-bit system by setting the enabled attribute of the configuration element to true in the run-time environment. [link](https://msdn.microsoft.com/en-us/library/xfhwa508%28v=vs.110%29.aspx) – GreenBear Oct 26 '15 at 21:57
  • Thank you all, it was very helpful ! – GreenBear Oct 26 '15 at 21:58
2

You need a new instance of the class:

    Dim myDict As New Dictionary(Of String, look)
    Dim oLook As New look
    oLook.shape = "square"
    oLook.color = "red"
    myDict.Add("first", oLook)
    oLook = New look '<<<<<<<<<<<<
    oLook.shape = "circle"
    oLook.color = "blue"
    myDict.Add("second", oLook)
    For Each key In myDict.Keys
        MsgBox(key & " - " & myDict(key).shape & ", " & myDict(key).color)
    Next
rheitzman
  • 2,247
  • 3
  • 20
  • 36
  • Thanks for the help. Can anybody explain me how this works? Do I get two oLook objects? How do I destroy them after I put a value into the dictionary? My dictionary will have about a billion keys, so I need to do it economical. – GreenBear Oct 26 '15 at 19:59
  • You are storing instances of your class Look in the dictionary. In the code above notice the second `New Look' - that create a new instance to store. If you have only a few combinations of shape and color, and a billion "records" to track this is not the right approach. If each of the billion are unique you need a billion records - and you wouldn't be storing this data in memory. – rheitzman Oct 26 '15 at 22:55
  • Thank you, rheitzman, you gave a correct answer, but the site does not allow me to mark two answers as correct. The code I wrote was a simplified version of what I actually need to do. All values will be unique. – GreenBear Oct 26 '15 at 23:08