Visual Basic 2012 Voorbeelden
   

visual basic 2012 broncode voorbeelden

Blijf op de hoogte van de recente aanpassingen op vbvoorbeelden!

Microsoft Visual Studio 2012Microsoft Developers Network - Visual BasicMicrosoft .NET Framework

22.19. SortedList en IComparable Elementen

Print Email Deel op Twitter Deel op Facebook

Dit artikel is gepubliceerd op maandag 15 oktober 2012 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.

22.19.1. SortedList.Add

In een SortedList worden de elementen steeds gesorteerd op hun key.  Er moet dan ook van elke key geweten zijn of die voor of na een andere key moet komen in de collectie.

In onderstaand voorbeeld proberen we toch twee elementen met een gelijke key toe te voegen aan de SortedList.  Een ArgumentException treedt hierbij op :
Visual Basic 2012 Broncode - Codevoorbeeld 574
Namespace SortedListAddExample
    Class Client
        Public Shared Sub Main()
            Dim sortedList1 As New SortedList
            '
            sortedList1.Add("key1", "value1")
            Try
                sortedList1.Add("key1", "value2")
            Catch ex As ArgumentException
                Console.WriteLine(ex.Message)
            End Try
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Item has already been added. Key in dictionary: 'key1'  Key being added: 'key1'
Het optreden van een exception, hier in dit geval specifiek een ArgumentException wordt hier opgevangen door middel van een Try ... Catch ....  Dit zorgt ervoor dat het optreden van exceptions niet leidt tot programma-afbreking.
Bij het optreden van een exception in het Try gedeelte wordt de code uitgevoerd die in het Catch gedeelte is gedefinieerd.

Voor meer details over (structured exception) handling kan je tercht in het desbetreffende topic.

Gezien in een SortedList de elementen steeds gesorteerd worden op hun key, moet men de keys steeds met elkaar kunnen vergelijken.
Ondanks dat ook de eerste parameter van de Add method van type Object is, wordt toch verondersteld dat het hier om onderling vergelijkbare objecten gaat.

Zo heeft bij de uitvoer van onderstaand voorbeeld de implementatie van de Add method van SortedList bij het toevoegen van het tweede element (1) nood aan de informatie of element met key2 voor of na element met key1 moet worden geplaatst.
Deze implementatie heeft echter geen idee hoe men twee objecten van het type KeyType hiervoor kan vergelijken.  De uitvoer van onderstaande regel (1) leidt dan ook tot een InvalidOperationException met de duidelijke Message "Failed to compare two elements ...".
Visual Basic 2012 Broncode - Codevoorbeeld 575
Namespace SortedListRequiresIComparableKeyExample
    Class KeyType
        Public Value As Integer
    End Class
    Class Client
        Public Shared Sub Main()
            Dim key1 As New KeyType With {.Value = 1}
            Dim key2 As New KeyType With {.Value = 2}
            '
            Dim sortedList1 As New SortedList
            '
            sortedList1.Add(key1, "value1")
            Try
                sortedList1.Add(key2, "value2")                            ' (1)
            Catch ex As InvalidOperationException
                Console.WriteLine(ex.Message)
            End Try
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Failed to compare two elements in the array.

22.19.2. IComparable Interface

Om dan toch objecten van type KeyType te kunnen gebruiken als key voor een SortedList moeten we aangeven hoe instanties van dit type onderling worden vergeleken.
Dit kan door middel van het implementeren van IComparable interface.  Indien deze wordt geïmplementeerd voorzie je immers van gedrag dat bepaald op basis van wat men twee objecten van dit type kan vergelijken om te weten welke voor of na het ander object in een ordening wordt geplaatst :
Visual Basic 2012 Broncode - Codevoorbeeld 576
Namespace IComparableKeyExample
    Class KeyType : Implements IComparable
        Public Value As Integer
        Public Function CompareTo(ByVal obj As Object) As Integer _
                                         Implements System.IComparable.CompareTo
            If obj Is Nothing Then
                CompareTo = 1                                              ' (1)
            ElseIf Not TypeOf obj Is KeyType Then
                Throw New ArgumentException("An invalid argument was " & _
                   "specified.  An argument of type KeyType is required.") ' (2)
            Else
                '                                                            (3)
                CompareTo = Me.Value.CompareTo(DirectCast(obj, KeyType).Value)
            End If
        End Function
    End Class
    Class Client1
        Public Shared Key1 As New KeyType With {.Value = 1}
        Public Shared Key2 As New KeyType With {.Value = 2}
        Public Shared Sub Main()
            Dim sortedList1 As New SortedList
            '
            sortedList1.Add(Key1, "value1")
            sortedList1.Add(Key2, "value2")
        End Sub
    End Class
End Namespace
De uitvoer van bovenstaand voorbeeld leidt niet tot een exception.  Nu weet de Add method van SortedList immers hoe het twee objecten van type KeyType kan vergelijken.

Elke object van eender welk type zou steeds als groter moeten worden beschouwd dan Nothing, hierdoor leveren we in de implementatie van CompareTo in dat geval een positieve waarde op (1), bijvoorbeeld 1.

Elke CompareTo implementatie zou een ArgumentException moeten opwerpen (2) indien men een instantie probeert te vergelijken met een object van een ander type.

De return waarde wordt hier gebaseerd op de CompareTo van Me.Value vergeleken met obj.Value (3).  Value is hier van type Integer en ook dit is een IComparable datatype.

Voor meer details over de IComparable interface, zou ik willen verwijzen naar het desbetreffende topic.

Hebben Key1 en Key2 toch dezelfde waarde (1) en worden ze met andere woorden ordinaal als gelijk beschouwd (2), dan levert onderstaande regel (3) natuurlijk wel weer een exception op :
Visual Basic 2012 Broncode - Codevoorbeeld 577
Namespace IComparableKeyExample
    Class Client2
        Public Shared Sub Main()
            Client1.Key2.Value = Client1.Key1.Value                        ' (1)
            Console.WriteLine(Client1.Key2.CompareTo(Client1.Key1))      ' 0 (2)
            '
            Dim sortedList1 As New SortedList
            '
            sortedList1.Add(Client1.Key1, "value1")
            Try
                sortedList1.Add(Client1.Key2, "value2")                    ' (3)
            Catch ex As ArgumentException
                Console.WriteLine(ex.Message)
            End Try
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
0
Item has already been added. Key in dictionary: 'IComparableKeyExample.KeyType'
Key being added: 'IComparableKeyExample.KeyType'
Dezelfde oorzaak dus als ons bovenstaand voorbeeld SortedListAddExample, ook daar werden de twee String instanties als ordinaal gelijk beschouwd :
Visual Basic 2012 Broncode - Codevoorbeeld 578
Namespace StringCompareToExample
    Class Client
        Public Shared Sub Main()
            Console.WriteLine("key1".CompareTo("key1")) ' 0
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
0
De conclusie is hoe dan ook dat het keytype voor een SortedList steeds de IComparable interface moet implementeren.

22.19.3. IComparable(Of T) is Niet Voldoende

Bemerk dat een IComparable(Of T) implementatie niet voldoende is.  KeyType die bijvoorbeeld IComparable(Of KeyType) is, is daarom nog niet automatisch IComparable.

Hier lopen we even voor door te verwijzen naar de generieke interface IComparable(Of T).  Dergelijk generiek datatype is niet rechtstreeks bruikbaar, het is immers niet compleet en moet nog worden ingevuld met een actueel generisch parametertype, bijvoorbeeld bij de invulling IComparable(Of KeyType).
Voor meer details over genericiteit kan je terecht in het desbetreffende hoofdstuk.

Zelfs al maak je KeyType IComparable(Of KeyType) dan nog moet je voor een correcte werking van KeyType als keytype voor een SortedList de gewone niet type-safe IComparable implementeren :
Visual Basic 2012 Broncode - Codevoorbeeld 579
Namespace IComparableOfTKeyExample
    Class KeyType : Implements IComparable, IComparable(Of KeyType)
        Public Value As Integer
        Private Function CompareTo(ByVal obj As Object) As Integer _
                                 Implements System.IComparable.CompareTo
            If Not TypeOf obj Is KeyType Then
                Throw New ArgumentException("An invalid argument was " & _
                         "specified.  An argument of type KeyType is required.")
            Else
                CompareTo = CompareTo(DirectCast(obj, KeyType))
            End If
        End Function
        Public Function CompareTo(ByVal other As KeyType) As Integer _
                             Implements System.IComparable(Of KeyType).CompareTo
            If other Is Nothing Then
                CompareTo = 1
            Else
                CompareTo = Me.Value.CompareTo(other.Value)
            End If
        End Function
    End Class
    Class Client
        Public Shared Sub Main()
            Dim key1 As New KeyType With {.Value = 1}
            Dim key2 As New KeyType With {.Value = 2}
            '
            Dim sortedList1 As New SortedList
            '
            sortedList1.Add(key1, "value1")
            sortedList1.Add(key2, "value2")
        End Sub
    End Class
End Namespace
Bovenstaande client functioneert zonder probleeem (zonder exception).

Het voordeel van IComparable(Of T) ten opzicht van IComparable is natuurlijk dat de eerstgenoemde typesafe is.  Zo merkt men in onderstaand voorbeeld reeds at compiletime op dat de expressie key1.CompareTo("dummy") niet is toegestaan (1).
De publieke CompareTo dwingt immers af dat een argumentwaarde van type KeyType wordt doorgegeven.  "dummy" van type String wordt door de compiler niet aanvaardt.

Dit in tegenstelling tot key2.CompareTo("dummy") die pas at runtime leidt tot een exception.  In type IComparableKeyExample.KeyType zit immers enkel een publieke CompareTo met argument van type Object.  Eender welk datatype van de expressie die de argumentwaarde voorstelt zal hier door de compiler worden aanvaard (2).
De implementatie van onze CompareTo in dit type werpt vervolgens wel at runtime een ArgumentException op :
Visual Basic 2012 Broncode - Codevoorbeeld 580
Namespace IComparableVersusIComparableOfTExample
    Class Client
        Public Shared Sub Main()
            Dim key1 As New IComparableOfTKeyExample.KeyType
            'key1.CompareTo("dummy") ' compile error                         (1)
            '
            Dim key2 As New IComparableKeyExample.KeyType
            key2.CompareTo("dummy")  ' runtime error                         (2)
        End Sub
    End Class
End Namespace
Het spreekt voor zich dat we liever at compiletime, in tegenstelling tot pas at runtime, op de hoogte worden gebracht van deze fout.

Dit artikel is gepubliceerd op maandag 15 oktober 2012 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.