JimmyJimm JimmyJimm - 7 months ago 20
Vb.net Question

Collection class of specific type containing basic features

Every time i use some class e.g Artikel as follows:

Public Class Artikel
Property ID As Integer
Property Nummer As String
Property Name As String
Property Position As Integer
End Class


For such classes i would like to have collection class. The features i would like to have is like:

--> Add (passing Artikel object)
--> Remove (passing Artikel object)
--> Sort entire collection (based on Position property desc/asc)
--> Compare two Artikels (pass by Artikels and tell by which property has to be compared)
--> Check whether two artikels equals
--> Every added artikel has to be marked by Key (so maybe dictionary)? <key><Artikel>
--> Remove Artikel (passing by Key index)


Could somone from you there tell me or even better provide example of collection class pass those requirments?

EDIT: Startup:

Artikel's collection:

Option Strict On
Public Class Articles

Public Property collection As Dictionary(Of Integer, Artikel)

Sub New()
'Initiate new collection
collection = New Dictionary(Of Integer, Artikel)
End Sub

'Add new Artikel to collection
Public Function AddToCollection(ByVal artikel As Artikel) As Boolean
collection.Add(artikel)
Return True
End Function

'Remove specific Artikel
Public Sub RemoveFromCollectionByArtikel(artikel As Artikel)
If Not IsNothing(collection) Then
collection.Remove(artikel)
End If
End Sub

'Get collection
Public Function GetCollection() As Dictionary(Of Integer, Artikel)
Return collection
End Function

'Sort collection by property position
Public Sub SortByPosition()
collection.Sort()
End Sub

'Remove specific sending keys and then reorder them
Public Sub RemoveAllMarkedAsDeleted(keys As List(Of Integer))
'-- Check whther anything has been marked as deleted
If keys.Count > 0 Then
For Each row In keys
collection.Remove(row)
Next
ReorderKeys()
End If

'Reorder all Artikels in collection
Private Sub ReorderKeys()
Dim newCollection As New Dictionary(Of Integer, Artikel)
Dim index As Integer = 0
For Each collitem In collection
newCollection.Add(index, collitem.Value)
index += 1
Next
collection.Clear()
collection = newCollection
End Sub


End Class


Artikel class (additionally i implemented IComparable to be able to sort)

Option Strict On
Public Class Artikel
Implements IComparable(Of Artikel)
Property ID As Integer
Property Nummer As String
Property Name As String
Property Position As Integer

Public Function CompareTo(pother As Artikel) As Integer Implements IComparable(Of Artikel).CompareTo 'we can sort because of this
Return String.Compare(Me.Position, pother.Position)
End Function
Public Shared Function FindPredicate(ByVal partikel As Artikel) As Predicate(Of Artikel)
Return Function(partikel2 As Artikel) partikel.ID = partikel2.ID
End Function
Public Shared Function FindPredicateByUserId(ByVal partikel As String) As Predicate(Of Artikel)
Return Function(partikel2 As Artikel) partikel = partikel2.ID
End Function
End Class

Answer

Parts of it look good, but I would ultimately do it a bit differently. First, consider overloads on the item class to make them easier to create and default initialization:

Public Class Article
    Property ID As Integer = -1
    Property Key As String = ""
    Property Name As String = ""
    Property Position As Integer = -1
    Property PubDate As DateTime = DateTime.Minimum

    Public Sub New()

    End Sub
    ' whatever minimum data a new item requires
    Public Sub New(k As String, n As String)
        Key = k
        Name = n
    End Sub
    ' full initialization:
    Public Sub New(k As String, n As String, pos As Int32,
                    pubDt As DateTime)
       ...
   End Sub
End Class

I added some properties for variety, and I suspect "Nummer" might be the "Key" mentioned in the OP, but whatever it is, I would add it to the Article class as that name, if it has some importance.

You might need a simple ctor for serialization (???). Some of these will find and use a Private parameterless constructor, but your code will be forced to use one of the overloads in order to provide some minimum level of data when a new one is created.


You probably do not need IComparable. That is typically for more complex comparisons, such as multiple or complex properties. An example is a carton or box:

If (width = Other.Width) AndAlso (height = Other.Height) Then
    Return 0
ElseIf (width = Other.Height) AndAlso (height = Other.Width) Then
    Return 0
End If

Plus more gyrations to work out which is "less" than the other. One reason you dont need it, is because If Art1.Postion > Art2.Postion is trivial. The other reason in your case, is because a Dictionary cannot be sorted.

Rather than a Dictionary, an internal List would work better for some of the things you describe but still allow you to have it act like a Dictionary to the extent you need it to. For this, I might build it using ICollection<T>:

Public Class ArticleCollection
    Implements ICollection(Of Article)

Pressing Enter after that line will add all the required methods including:

Public Sub Add(item As Article) Implements ICollection(Of Article).Add

Public Sub Clear() Implements ICollection(Of Article).Clear

Public Function Contains(item As Article) As Boolean Implements ICollection(Of Article).Contains

Public ReadOnly Property Count As Integer Implements ICollection(Of Article).Count

Public Function Remove(item As Article) As Boolean Implements ICollection(Of Article).Remove

It remains completely up to you how these are implemented. It also doesn't rule out adding methods such as RemoveAt(int32) or RemoveByKey(string) depending on what you need/how it will be used. One of the benefits to ICollection(Of T) is that it includes IEnumerable which will allow use for each loops (once you write the Enumerator): For Each art In Articles

To emulate a dictionary to allow only one item with a specific property value:

Public Class ArticleCollection
    Implements ICollection(Of Article)

    Private mcol As List(Of Article)
    ...
    Public Sub Add(item As Article) Implements ICollection(Of Article).Add
        ' check for existing key
        If KeyExists(item.Key) = False Then
            mcol.Add(item)
        End If
    End Sub

You can also overload them:

' overload to match Article ctor overload
Public Sub Add(key As String, name As String)
     If KeyExists(key) = False Then
        ' let collection create the new item
        ' with the minimum required info
        mcol.Add(New Article(key, name))
    End If
End Sub

If you add an Item Property, you can index the collection ( Articles(3) ):

Property Item(ndx As Int32) As Article
    Get
        If ndx > 0 AndAlso ndx < mcol.Count Then
            Return mcol(ndx)
        Else
            Return Nothing
        End If
    End Get
    Set(value As Article)
        If ndx > 0 AndAlso ndx < mcol.Count Then
            mcol(ndx) = value
        End If
    End Set
End Property

' overload for item by key:
Public Property Item(key As String) As Article

An Add method and an Item Property will be important if the collection will display in the standard NET CollectionEditor.

There are several ways to implement sorting. The easiest is to use linq in the code which uses your collection:

Articles = New ArticleCollection
' add Article items
Dim ArticlesByDate = Articles.OrderBy(Function(s) s.PubDate).ToList()

Where PubDate is one of the Article properties I added. The other way to handle sorting is by the collection class returning a new collection (but it is so simple to do, there is little need for it):

Friend Function GetSortedList(bSortAsc As Boolean) As List(Of Article)
    If bSortAsc Then
        Return mcol.OrderBy(Function(q) q.PubDate).
                ThenBy(Function(j) j.Position).ToList()
    Else
        Return mcol.OrderByDescending(Function(q) q.PubDate).
                ThenByDescending(Function(j) j.Position).ToList()
    End If
End Function

Whether it implements ICollection(Of T), inherits from ICollection(Of T) or does work off a Dictionary depends entirely on what this is, how it is used and whatever rules and restrictions there are (including if it will be serialized and how). These are not things we know.

MSDN has an article on Guidelines for Collections which is excellent.