In regards to CatProduct, I left that out but Visual Studio can auto create it for you although here it is in the code below. Concerting unique properties, the base Product class should have all properties even if not used for some products.
Public Class CatProduct
Public Property Category As Category
Public Property List As List(Of Product)
End Class
Think of when a database is properly designed for orders as shown below. Perhaps some orders don't use discount or some products don't use discontinue. It's incorrect to stored some product types differently instead in this type of situation the property is empty in both cases, no harm no foul.
But if you want to break the rules you can by using base classes and overridable properties as per below.
Visuals
Base class
Public Class Base
Public Property Id() As Integer
Public Overridable Property Name() As String
End Class
Revised Product class
Public Class Product
Inherits Base
Implements INotifyPropertyChanged
Private _name As String
Private _category As Category
Private _price As Decimal
Private _quantity As Integer
Public Overrides Property Name() As String
Get
Return _name
End Get
Set
_name = Value
OnPropertyChanged()
End Set
End Property
Public Property Category() As Category
Get
Return _category
End Get
Set
_category = Value
OnPropertyChanged()
End Set
End Property
Public Property Price() As Decimal
Get
Return _price
End Get
Set
_price = Value
OnPropertyChanged()
End Set
End Property
Public Property Quantity() As Integer
Get
Return _quantity
End Get
Set
_quantity = Value
OnPropertyChanged()
End Set
End Property
Public Overrides Function ToString() As String
Return $"{Name} {Price}"
End Function
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional propertyName As String = Nothing)
PropertyChangedEvent?.Invoke(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Other class with all properties
For above but includes cost while cost should truly be in the classes above.
Public Class SomeOther
Inherits Product
Private _cost As Integer
Public Property Cost() As Integer
Get
Return _cost
End Get
Set
_cost = Value
OnPropertyChanged()
End Set
End Property
End Class