Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Andrzejek on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

user supplied sort function

Status
Not open for further replies.

jges

Technical User
Oct 24, 2003
537
US
I have a class that has a collection of objects (a generic list). I'd like the user of my class to be able to supply a custom sort function, similar to the example code below. However, in my actual code, I'd like to keep the list of objects private, since the user doesn't really need access to them (except that it's the only successful way I've found so far to allow a user supplied sort function). I'd like to pass in the custom sort function as a property/method of my class or have a .Sort() method that accepts the custom function as input. My google searches have led me to 'delegates', which sound exactly like what I think I'm looking for, but I've not been able to translate their example code into working code for my situation.

Here's some working code but not quite what I want, as it gives public access to the list of objects.

Code:
Module Module1

    Sub Main()

        Dim theWidgetSorter As New widgetSorter
        With theWidgetSorter.Widgets
            .Add(New Widget("penny"))
            .Add(New Widget("nickel"))
            .Add(New Widget("dime"))
            .Add(New Widget("quarter"))
        End With

        Console.WriteLine("original order:")
        For Each tempWidget In theWidgetSorter.Widgets
            Console.WriteLine("  " & tempWidget.Name)
        Next
        Console.WriteLine("")

        theWidgetSorter.Widgets.Sort()
        Console.WriteLine("alphabetical")
        For Each tempWidget In theWidgetSorter.Widgets
            Console.WriteLine("  " & tempWidget.Name)
        Next
        Console.WriteLine("")

        theWidgetSorter.Widgets.Sort(AddressOf CompareNameLength)
        Console.WriteLine("custom sort")
        For Each tempWidget In theWidgetSorter.Widgets
            Console.WriteLine("  " & tempWidget.Name)
        Next
        Console.WriteLine("")

        Console.ReadLine()


    End Sub

    Public Function CompareNameLength(ByVal x As Widget, ByVal y As Widget) As Integer

        If x.Name.Length > y.Name.Length Then
            Return 1
        End If

        If x.Name.Length < y.Name.Length Then
            Return -1
        End If

        If x.Name.Length = y.Name.Length Then
            Return 0
        End If

    End Function


End Module


Class Widget
    Implements IComparable(Of Widget)

    Private _name As String
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Sub New(ByVal widgetName As String)
        Me.Name = widgetName
    End Sub

    Public Function CompareTo(other As Widget) As Integer Implements System.IComparable(Of Widget).CompareTo

        ' A null value means that this object is greater. 
        If other Is Nothing Then
            Return 1
        Else

            Return Me.Name.CompareTo(other.Name)
        End If

    End Function
End Class

Class widgetSorter

    Private _widgetList As New List(Of Widget)
    Public Property Widgets() As List(Of Widget)
        Get
            Return _widgetList
        End Get
        Set(ByVal value As List(Of Widget))
            _widgetList = value
        End Set
    End Property

    Public Delegate Function CustomSort(ByVal x As Widget, ByVal y As Widget) As Integer
    Private myCustomSort As CustomSort
    Public Property CustomSortDelegate() As CustomSort
        Get
            Return myCustomSort
        End Get
        Set(ByVal value As CustomSort)
            myCustomSort = value
        End Set
    End Property

    Public Sub SortWidgets()

        If IsNothing(myCustomSort) Then
            'sort alphabetically
            _widgetList.Sort()
        Else
            'use custom sort function
            _widgetList.Sort(myCustomSort)
        End If

    End Sub

End Class
 
And here's some code where I've tried to use a delegate, but I get an Invalid Cast Exception: unable to cast object of type 'CustomSort' to type 'System.Collections.Generic.IComparer'. I don't understand why the previous code works by passing in the "AddressOf" the sort function, but this code won't work by passing in a delegate?

Code:
Module Module1

    Sub Main()

        Dim theWidgetSorter As New widgetSorter
        With theWidgetSorter.Widgets
            .Add(New Widget("penny"))
            .Add(New Widget("nickel"))
            .Add(New Widget("dime"))
            .Add(New Widget("quarter"))
        End With

        Console.WriteLine("original order:")
        For Each tempWidget In theWidgetSorter.Widgets
            Console.WriteLine("  " & tempWidget.Name)
        Next
        Console.WriteLine("")

        theWidgetSorter.Widgets.Sort()
        Console.WriteLine("alphabetical")
        For Each tempWidget In theWidgetSorter.Widgets
            Console.WriteLine("  " & tempWidget.Name)
        Next
        Console.WriteLine("")

[highlight #FCE94F]        Dim theCustomSort As widgetSorter.CustomSort = AddressOf CompareNameLength
        theWidgetSorter.CustomSortDelegate = theCustomSort
        theWidgetSorter.SortWidgets()[/highlight]

        'theWidgetSorter.Widgets.Sort(AddressOf CompareNameLength)
        Console.WriteLine("custom sort")
        For Each tempWidget In theWidgetSorter.Widgets
            Console.WriteLine("  " & tempWidget.Name)
        Next
        Console.WriteLine("")

        Console.ReadLine()


    End Sub

    Public Function CompareNameLength(ByVal x As Widget, ByVal y As Widget) As Integer

        If x.Name.Length > y.Name.Length Then
            Return 1
        End If

        If x.Name.Length < y.Name.Length Then
            Return -1
        End If

        If x.Name.Length = y.Name.Length Then
            Return 0
        End If

    End Function


End Module


Class Widget
    Implements IComparable(Of Widget)

    Private _name As String
    Public Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Sub New(ByVal widgetName As String)
        Me.Name = widgetName
    End Sub

    Public Function CompareTo(other As Widget) As Integer Implements System.IComparable(Of Widget).CompareTo

        ' A null value means that this object is greater. 
        If other Is Nothing Then
            Return 1
        Else

            Return Me.Name.CompareTo(other.Name)
        End If

    End Function
End Class

Class widgetSorter

    Private _widgetList As New List(Of Widget)
    Public Property Widgets() As List(Of Widget)
        Get
            Return _widgetList
        End Get
        Set(ByVal value As List(Of Widget))
            _widgetList = value
        End Set
    End Property

    Public Delegate Function CustomSort(ByVal x As Widget, ByVal y As Widget) As Integer
    Private myCustomSort As CustomSort
    Public Property CustomSortDelegate() As CustomSort
        Get
            Return myCustomSort
        End Get
        Set(ByVal value As CustomSort)
            myCustomSort = value
        End Set
    End Property

    Public Sub SortWidgets()

        If IsNothing(myCustomSort) Then
            'sort alphabetically
            _widgetList.Sort()
        Else
            'use custom sort function
            _widgetList.Sort(myCustomSort)
        End If

    End Sub

End Class
 
Ok, I got rid of all the delegate stuff and added the following sort method:

Code:
 Public Sub SortWidgets(ByVal sortFunction As System.Comparison(Of Widget))

     _widgetList.Sort(sortFunction)

 End Sub

Now I can write my own sort function and pass it in like this:

Code:
myObject.Sort(AddressOf customSortFunction)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top