Sorting a Custom Collection with Nested Class Types

I have the need to sort a custom collection that contains sub classes.  For example,

I've structured my classes like this:

Public Class Machine

  
Private _Model as Model
  
Public Property vModel as Model
    
Get 
      Return 
_Model
    
End Get
    Set 
(ByVal Value as Model) 
      _Model = Value
    
End Set
  End Property
  
  Public Sub New
()
    _Model = 
new Model
  
End Sub
  
End Class

Public Class 
Model

  
Private _ModelName as String
  Public Property 
ModelName as String
    Get 
      Return 
_ModelName
    
End Get
    Set 
(ByVal Value as String
      _ModelName = Value
    
End Set
  End Property
  
  Public Sub New
()
    _ModelName = ""
  
End Sub
  
End Class

I then made a collection of Machine objects like this:

Public Class MachineList

    
Inherits CollectionBase

    
Default Public Property Item(ByVal Index As IntegerAs Machine
        
Get
            Return CType
(List.Item(Index), Machine)
        
End Get
        Set
(ByVal Value As Machine)
            List.Item(Index) = Value
        
End Set
    End Property

    Public Function 
Add(ByVal Item As Machine) As Integer
        Return 
List.Add(Item)
    
End Function

    Public Sub 
Remove(ByVal Item As Machine)
        List.Remove(Item)
    
End Sub

End Class

Pretty straight-forward, right?

Well, there was no easy way to sort this.  It's one of the Unsortable classes.  As I was searching through the net, I found this article by Jan Tielens, which claims to be able to sort the unsortable collection.  In normal circumstances, it does.  However, I have nested custom classes.  His solution only works on the first level.

So, I set to work trying to figure out a way, using Reflection, to pass in the Property name that I wanted to compare.  (ie: "Model.ModelName").  Well, I parsed the Property Name at the Period, and used reflection to get the values in string form. Then, determined if they were numeric or not, and I compared them, and returned 0, -1, or 1, depending on the values.  I then took my routine, and stuck it into Jan's Compare Routine.  Voila, a custom nested class sorter.  It'll go as deep as you want it to go. 

At this point, it's dirty.  I'll be working on a way to clean it up a bit, but it does what I want it to.


Public Function Compare(ByVal As ObjectByVal As ObjectAs Integer _
      
Implements System.Collections.IComparer.Compare
        Dim 
i() As Object
        Dim 
As Integer = 0

        
Dim tempSP() As String = PropertyToSort.Split(".")

        
Dim v(tempSP.GetUpperBound(0)) As Object
        Dim 
b(tempSP.GetUpperBound(0)) As Object

        Dim 
temp As String

        Dim 
As Machine = CType(x, Machine)
        
Dim As Machine = CType(y, Machine)

        
For Each temp In tempSP

            v(c) = 
New Object()
            b(c) = 
New Object()

            
Select Case temp

                
Case "Model"
                    v(c) = m.GetType.GetProperty(temp).GetValue(m, i)
                    b(c) = n.GetType.GetProperty(temp).GetValue(n, i)
                
Case Else
                    If 
IsNothing(v) Then
                        
v(c) = m.GetType.GetProperty(temp).GetValue(m, i)
                        b(c) = n.GetType.GetProperty(temp).GetValue(n, i)
                    
Else
                        If 
c > 0 Then

                            
v(c) = CStr(v(c - 1).GetType.GetProperty(temp).GetValue(v(c - 1), i))
                            b(c) = 
CStr(b(c - 1).GetType.GetProperty(temp).GetValue(b(c - 1), i))
                        
Else
                            
v(c) = CStr(m.GetType.GetProperty(temp).GetValue(m, i))
                            b(c) = 
CStr(n.GetType.GetProperty(temp).GetValue(n, i))
                        
End If

                    End If
            End Select

            
c = c + 1

        
Next

        
c = c - 1

        
If IsNumeric(b(c)) And IsNumeric(v(c)) Then

            If 
SortOrder = Windows.Forms.SortOrder.Ascending Or SortOrder = Windows.Forms.SortOrder.None Then
                If CLng
(v(c)) > CLng(b(c)) Then
                    Return 
1
                
End If
                If CLng
(v(c)) = CLng(b(c)) Then
                    Return 
0
                
End If
                If CLng
(v(c)) < CLng(b(c)) Then
                    Return 
-1
                
End If
            Else
                If CLng
(v(c)) < CLng(b(c)) Then
                    Return 
1
                
End If
                If CLng
(v(c)) = CLng(b(c)) Then
                    Return 
0
                
End If
                If CLng
(v(c)) > CLng(b(c)) Then
                    Return 
-1
                
End If
            End If

        Else

            If 
SortOrder = Windows.Forms.SortOrder.Ascending Or SortOrder = Windows.Forms.SortOrder.None Then

                Return String
.Compare(CStr(v(c)), CStr(b(c)))

            
Else

                Return String
.Compare(CStr(b(c)), CStr(v(c)))

            
End If

        End If

    End Function

 

Print | posted on Thursday, January 12, 2006 4:09 PM

Feedback

# re: Sorting a Custom Collection with Nested Class Types

left by Galawyn at 11/26/2007 7:36 PM Gravatar
Dim m As Machine = CType(x, Machine)
Dim n As Machine = CType(y, Machine)
Case "Model"...

is not very generic in this way :|

have you ever fix it?

# re: Sorting a Custom Collection with Nested Class Types

left by Kyle at 2/8/2008 6:45 AM Gravatar
Hi Galawyn,

Nope. Never had the need. Though I think it would probably come in handy...

K-
Title  
Name
Email (never displayed)
Url
Comments   
Please add 5 and 1 and type the answer here: