One needs to create a new instance of the Product class for each iteration of the for loop.
Each programming language has it's own Naming Conventions which you may consider adopting (the word Class, isn't typically appended to the name of the class). Also, public properties are preferred over public fields. See Properties vs Fields – Why Does it Matter? and Auto-Implemented Properties (Visual Basic) for more information.
Public Class Product
Public Property Id As Integer
Public Property Name As String
Public Property Description As String
End Class
Sometimes one would like to sort the products. For this we can implement IComparable. We'll sort by 'Id'.
Public Function CompareTo(other As Product) As Integer Implements IComparable(Of Product).CompareTo
'sort by 'Id'
If Id = other.Id Then
Return 0
ElseIf Id > other.Id Then
Return 1
Else
Return -1
End If
End Function
In this code example 'Id' is unique. However, what if 'Id' isn't unique by itself, but the combination of 'Id' and 'Name' is unique. Then, we'd first compare 'Id', then 'Name'.
Public Class Product
Implements IComparable(Of Product)
Public Property Id As Integer
Public Property Name As String
Public Property Description As String
Public Function CompareTo(other As Product) As Integer Implements IComparable(Of Product).CompareTo
'sort by 'Id', then 'Name'
If Id = other.Id Then
If String.Compare(Name, other.Name, StringComparison.OrdinalIgnoreCase) = 0 Then
Return 0
ElseIf String.Compare(Name, other.Name, StringComparison.OrdinalIgnoreCase) > 0 Then
Return 1
Else
Return -1
End If
ElseIf Id > other.Id Then
Return 1
Else
Return -1
End If
End Function
End Class
For further study, also see IComparer.
One may wish to override the ToString() method, so that when ToString() is called, we get the desired output. When ToString() is called, we'll output both 'Id' and 'Name' - you'll notice that I've chosen to use Interpolated Strings
So, now our class will be:
Public Class Product
Implements IComparable(Of Product)
Public Property Id As Integer
Public Property Name As String
Public Property Description As String
Public Function CompareTo(other As Product) As Integer Implements IComparable(Of Product).CompareTo
'sort by 'Id'
If Id = other.Id Then
Return 0
ElseIf Id > other.Id Then
Return 1
Else
Return -1
End If
End Function
Public Overrides Function ToString() As String
'when ToString() is called, return both 'Id' and 'Name'
Return $"{Id}: {Name}"
End Function
End Class
Now, we'll create a Function that populates a SortedDictionary and returns it. Each iteration of the for loop must create a new instance of Product. For the product name I've appended a letter of the alphabet to the word Product based on the value of i. In the code below, I've used an initializer to set the property values. See How to: Declare an Object by Using an Object Initializer (Visual Basic) for more information.
Private Function CreateTestData() As SortedDictionary(Of Integer, Product)
Dim products As SortedDictionary(Of Integer, Product) = New SortedDictionary(Of Integer, Product)()
Dim alphabet As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
For i As Integer = 0 To 3
'create new instance and set values
Dim prod As Product = New Product() With {.Id = i, .Name = $"Product {alphabet(i)}"}
'only add to dictionary if it doesn't already exist
If Not products.ContainsKey(i) Then
products.Add(i, prod)
End If
Next
'for debugging, output the dictionary contents
For Each kvp As KeyValuePair(Of Integer, Product) In products
Debug.WriteLine(kvp.Value.ToString())
Next
Return products
End Function
Output:
0: Product A
1: Product B
2: Product C
3: Product D
Update:
When one creates a class, by default, one get's the empty (or default) constructor without having to specify it. If desired one can explicitly define it, by adding the following code to the class:
Public Sub New()
End Sub
As mentioned in a different answer, if desired, rather than using an initializer (with the empty constructor), one could use a custom constructor. However, one thing to note, is that once one defines a custom constructor the empty (or default) constructor is no longer available unless we explicitly define it. When explicitly defining constructors, one needs to define every constructor that one desires to have, including the empty (default) constructor.
In the code below, I've defined a constructor that takes parameters: 'id', 'name' and 'description' - I've chosen to make 'description' optional.
Product:
Public Class Product
Implements IComparable(Of Product)
Public Property Id As Integer
Public Property Name As String
Public Property Description As String
Public Sub New(id As Integer, name As String, Optional description As String = Nothing)
Me.Id = id
Me.Name = name
Me.Description = description
End Sub
End Class
Usage 1:
Dim prod As Product = New Product(i, $"Product {alphabet(i)}")
Usage 2:
Dim prod As Product = New Product(i, $"Product {alphabet(i)}", "This is the product description")
Usage 3:
Dim prod As Product = New Product(i, Nothing)
Here's a version that contains both the empty (default) constructor, as well as, a custom constructor.
Product:
Public Class Product
Implements IComparable(Of Product)
Public Property Id As Integer
Public Property Name As String
Public Property Description As String
Public Sub New()
End Sub
Public Sub New(id As Integer, name As String, Optional description As String = Nothing)
Me.Id = id
Me.Name = name
Me.Description = description
End Sub
End Class
Below, you'll notice that one can either use the custom constructor, or the initializer - which uses the empty (default) constructor.
Usage 1:
Dim prod As Product = New Product(i, $"Product {alphabet(i)}")
Usage 2:
Dim prod As Product = New Product(i, $"Product {alphabet(i)}", "This is the product description")
Usage 3:
Dim prod As Product = New Product(i, Nothing)
Usage 4:
Dim prod As Product = New Product() With {.Id = i, .Name = $"Product {alphabet(i)}"}