|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
22.18.1. SortedList.AddIn 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 2010 Broncode 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 ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 Broncode 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") Catch ex As InvalidOperationException Console.WriteLine(ex.Message) End Try Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output Failed to compare two elements in the array. boven
22.18.2. IComparable InterfaceOm 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 2010 Broncode 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 ElseIf Not TypeOf obj Is KeyType Then Throw New ArgumentException( "An invalid argument was " & _ "specified. An argument of type KeyType is required.") Else 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 ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 Broncode Namespace IComparableKeyExample Class Client2 Public Shared Sub Main() Client1.Key2.Value = Client1.Key1.Value Console.WriteLine(Client1.Key2.CompareTo(Client1.Key1)) Dim sortedList1 As New SortedList sortedList1.Add(Client1.Key1, "value1") Try sortedList1.Add(Client1.Key2, "value2") Catch ex As ArgumentException Console.WriteLine(ex.Message) End Try Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 Broncode Namespace StringCompareToExample Class Client Public Shared Sub Main() Console.WriteLine( "key1".CompareTo( "key1")) Console.ReadLine() End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 0 De conclusie is hoe dan ook dat het keytype voor een SortedList steeds de IComparable interface moet implementeren. boven
22.18.3. IComparable(Of T) is Niet VoldoendeBemerk 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 2010 Broncode 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 ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 2010 Broncode Namespace IComparableVersusIComparableOfTExample Class Client Public Shared Sub Main() Dim key1 As New IComparableOfTKeyExample. KeyType Dim key2 As New IComparableKeyExample. KeyType key2.CompareTo( "dummy") End Sub End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
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 zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|