I am trying to store a class object in an array. I have created the example below for my problem to make it simple.
I want to add an object of a class to an array in a loop. The object is changed at each loop pass and then added to the array. The problem is that with each loop pass the previous objects in the array are overwritten.
Public Class Itemproperties
Public Number As String
Public Hight As Single
End Class
Public ItemStorage(6) As Itemproperties
Public Item As New Itemproperties
Private Sub ClassObjectToArray(sender As Object, e As EventArgs)
For i As Integer = 0 To ItemStorage.Length - 1
Item.Hight = i + 1
ItemStorage(i) = Item
Console.WriteLine(ItemStorage(0).Hight)
Next
End Sub
The output should be 1 1 1 1 1 1 1 1
but is 1 2 3 4 5 6 7
.
It seems that it is not the object that is added to the array, but rather a pointer to the object.
If I try the same system on a very simple example with an integer, it works without problems:
Dim x As Integer
Dim testarray(6) As Integer
For i As Integer = 0 To testarray.Length - 1
x = i + 1
testarray(i) = x
Console.WriteLine(testarray(0))
Next
Does anyone have an idea what the problem is?
I have tried out whether I have initialised the array or the individual elements incorrectly. If I break down the class and add it individually to the array it works, but then I have to initialise each element beforehand with testarray(i) = New Itemproperties
.
Item.Hight = i + 1
ItemStorage(i) = New Itemproperties
ItemStorage(i).Hight = Item.Hight
If I remove the breakdown but still initialise each element, unfortunately nothing changes.
What a great question!
Joel on Software once noted that a class full of people having learned some programming language and then hit the part about "pointers" in the class. That's when the class drops from 70 enrolled down to less then 30!!!
The simple way to explain this?
When you use a variable like integer or string?
They ARE a variable and they are referenced by "value".
However, when you create/use an object? Your variable is ONLY a pointer to the actual object!!!
So, say this code:
Public Class Itemproperties
Public Number As String
Public Hight As Single
End Class
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim a As New Itemproperties
Dim b As Itemproperties = a
Dim c As Itemproperties = a
a.Hight = 5000
Debug.Print($"b height = {b.Hight}")
Debug.Print($"c height = {c.Hight}")
End Sub
Output:
So, a, b, and c are ALL THE SAME variable!!!!
So, your variable is in fact a pointer to the ONE object. A nice way to think of this is when you pass values to a sub routine. Are you using By Val (a new value (copy) is passed, and thus changes in the sub don't travel back to the caller routine).
Or, are you using By Ref (by reference, a pointer!). When you use By Ref, you are NOT passing a copy of the variable to the sub routine, but in fact are passing a reference (pointer).
Hence a copy of the variable is not made, and any changes in the sub to that passed value will be returned.
So, in your case?
You are creating ONE instance of the class, and sending it over and over to the array. The result is the array is JUST holding a list of pointers to the ONE class, and each element in the array points to the ONE instance of that class. (just like b and c in the above).
The simple solution to the above is to ensure that you create a new instance of the class each time, and then shove that into your array.
Hence, like this:
Dim MyProps(10) As Itemproperties
For i = 1 To 10
Dim MyItem As New Itemproperties
MyItem.Hight = 1000 * i
MyProps(i) = MyItem
Next
For i = 1 To 10
Debug.Print($"height for index {i} = {MyProps(i).Hight}")
Next
Output:
So, just remember that "objects" in a variable are not in fact the object, but ONLY a pointer (reference) to the real object in memory.
So, create a new instance each time, and you will be fine.