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

21.3. IComparable Interface

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.

21.3.1. System.IComparable

In de FCL (Framework Class Library) zitten reeds tal van voorgedefinieerde interfacetypes.  Deze zijn dus meteen klaar voor gebruik en worden zelfs al in andere types van de FCL gebruikt.

Een voorbeeld daarvan is de IComparable interface uit de System namespace.  Deze wordt onder andere gebruikt in de klassen System.Array en System.Collections.ArrayList waar men beschikt over Sort methods.

Deze Sort methods gaan een bepaald sorteringsprincipe toepassen op de elementen van de collectie.  Bij numerieke inhoud van een Array of ArrayList zal Sort bijvoorbeeld de waarden van klein naar groot sorteren, bij Dates zal dit van oud naar nieuw zijn, ... .
Visual Basic 2012 Broncode - Codevoorbeeld 460
Namespace Example1
    Class Client
        Public Shared Sub Main()
            Dim byteArray1 As Byte() = New Byte() {3, 2, 1}
            Array.Sort(byteArray1)
            For Each item As Byte In byteArray1
                Console.Write(item.ToString() & " ")
            Next
            Console.WriteLine()
            '
            Dim arrayList1 As ArrayList = New ArrayList()
            arrayList1.Add(New Date(2006, 10, 22))
            arrayList1.Add(New Date(2006, 10, 21))
            arrayList1.Add(New Date(2006, 10, 20))
            arrayList1.Sort()
            For Each item As Date In arrayList1
                Console.Write(item.ToString() & " ")
            Next
            Console.WriteLine()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
1 2 3
20/10/2006 0:00:00 21/10/2006 0:00:00 22/10/2006 0:00:00
De manier waarop de elementen van een collectie gesorteerd worden is dus afhankelijk van het elementtype.  Elk type die je definieert kan de IComparable interface implementeren, om zo zelf te bepalen hoe elementen van dat type met elkaar vergeleken moeten worden.

Als we elementen van onze eigen user defined types wensen te sorteren in onder andere een Array of een ArrayList.  Dan kunnen we dit doen door de IComparable interface in ons type te implementeren.

Hiervoor hoeven we enkel een implementatie te voorzien voor : Function CompareTo(ByVal obj As Object) As Integer

Dit is een functie die een negatieve waarde, nul of positieve waarde oplevert naargelang het doorgegeven argument respectievelijk "groter", "gelijk" of "kleiner" is dan het object zelf (waarop de CompareTo method wordt aangeroepen).

Door deze implementatie te voorzien kunnen methods als Sort (uit bijvoorbeeld de types Array, ArrayList, ...) twee elementen met elkaar vergelijken gebaseerd op de terugkeerwaarde van deze CompareTo.
Om elementen in een verzameling te sorteren, moet je immers in staat zijn twee elementen onderling met elkaar te vergelijken om te weten of het ene element voor of achter het andere element geplaatst moet worden.

In onderstaand voorbeeld gaan we de volgorde in een verzameling waarop elementen van het type Figure moeten geplaatst worden baseren op de GetArea() van deze figuren :
Visual Basic 2012 Broncode - Codevoorbeeld 461
Namespace Example2
    MustInherit Class Figure : Implements IComparable
        Public MustOverride Function GetArea() As Double
        Private Function CompareTo(ByVal obj As Object) As Integer _
                                                 Implements System.IComparable.CompareTo
            CompareTo = CompareTo(DirectCast(obj, Figure))
        End Function
        Public Function CompareTo(ByVal other As Figure) As Integer
            CompareTo = Me.GetArea().CompareTo(other.GetArea())
            Select Case Me.GetArea()
                Case Is > other.GetArea()
                    CompareTo = 1
                Case Is = other.GetArea()
                    CompareTo = 0
                Case Is < other.GetArea()
                    CompareTo = -1
            End Select
        End Function
        Public Overrides Function ToString() As String
            ToString = GetArea.ToString()
        End Function
    End Class
    Class Square : Inherits Figure
        Public Property Side As Double
        Public Overrides Function GetArea() As Double
            GetArea = Side ^ 2
        End Function
    End Class
    Class Circle : Inherits Figure
        Public Property Radius As Double
        Public Overrides Function GetArea() As Double
            GetArea = (Radius ^ 2) * System.Math.PI
        End Function
    End Class
    Class Client
        Public Shared Sub Main()
            Dim square1 As Square = New Square With {.Side = 5}
            Dim square2 As Square = New Square With {.Side = 3}
            Dim circle1 As Circle = New Circle With {.Radius = 1}
            '
            Dim figures1 As Figure() = New Figure() {square1, circle1, square2}
            For Each item As Figure In figures1
                Console.Write(item.ToString() & "  ")
            Next
            Console.WriteLine()
            Array.Sort(figures1)
            For Each item As Figure In figures1
                Console.Write(item.ToString() & "  ")
            Next
            Console.WriteLine()
            '
            Dim figures2 As ArrayList = New ArrayList
            figures2.Add(square1)
            figures2.Add(circle1)
            figures2.Add(square2)
            For Each item As Figure In figures2
                Console.Write(item.ToString() & "  ")
            Next
            Console.WriteLine()
            figures2.Sort()
            For Each item As Figure In figures2
                Console.Write(item.ToString() & "  ")
            Next
            Console.WriteLine()
            '
            Console.WriteLine(square1.CompareTo(circle1))                  ' (1)
            Console.WriteLine(circle1.CompareTo(square1))                  ' (2)
            'square2.CompareTo(New Date(2006, 10, 24))                     ' (3)
            Dim somethingComparable As IComparable = square2
            'somethingComparable.CompareTo(New Date(2006, 10, 24))         ' (4)
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
25  3,14159265358979  9
3,14159265358979  9  25
25  3,14159265358979  9
3,14159265358979  9  25
1
-1
Ook abstract klassen kunnen een interface implementeren.  Abstract klassen kunnen voor de members uit het interfacetype een implementatie voorzien.
Toch is dit niet noodzakelijk, ook in een MustOverride member kan een Implements clausule worden opgenomen.

21.3.2. Private Implementation

In bovenstaand voorbeeld wordt "private implementation" toegepast.  Men spreekt over private implementation in het geval dat members uit een interfacetype niet worden geïmplementeerd door een Public member.
Dit zou men bijvoorbeeld kunnen gebruiken (zoals ook in bovenstaand voorbeeld) om te vermijden dat niet typesafe members aan de interface ( publieke members) van het implementerende type worden toegevoegd.
Een typesafe CompareTo method werd wel toegevoegd, om de mogelijkheid te voorzien meerdere Figure objecten met elkaar te vergelijken.  Aan deze method kunnen nu enkel Figure expressies worden doorgegeven.  Regel (1) en (2) zijn hiervan voorbeelden.  Regel (3) demonstreert dat het niet mogelijk is niet Figure expressies door te geven.
Wat echter wel nog mogelijk is, is om via expressies van het type IComparable de niet typesafe CompareTo method aan te roepen (zoals regel (4) illustreert).  Dit zullen we echter nooit kunnen verhinderen.  Een runtimefout treed op bij de uitvoer van deze regel.

Een ander manier om enkel een typesafe CompareTo method te voorzien, bestaat erin in plaats van de System.IComparable interface de System.IComparable(Of T) interface te implementeren.
In het hoofdstuk over genericiteit wordt deze interface behandeld.

Overigens is het zo dat een interfacetype enkele kan worden geïmplementeerd in een klasse, een interface kan zelf geen andere interface implementeren, maar kan wel van andere interfaces overerven.

De implementatie voor de CompareTo method uit het interfacetype IComparable in de klasse Figure kan nog vereenvoudigd worden.

We baseren de CompareTo returnwaarde op de GetArea, door de GetArea van het argument met de GetArea van het object zelf te vergelijken.

Deze GetArea functie is van het type Double.  Nu weten me ook dat bijvoorbeeld een Array met elementen van het type Double kan worden gesorteerd via de Array.Sort method.  Ook dit komt doordat het type Double in een implementatie van de IComparable interface voorziet.
We kunnen de implementatie voor onze CompareTo implementatie vervolgens gewoon delegeren naar de implementatie voor CompareTo die het Double type hiervoor heeft voorzien.
Visual Basic 2012 Broncode - Codevoorbeeld 462
Namespace Example4
    MustInherit Class Figure : Implements IComparable
        Public MustOverride Function GetArea() As Double
        Private Function CompareTo(ByVal obj As Object) As Integer _
                                         Implements System.IComparable.CompareTo
            CompareTo = CompareTo(DirectCast(obj, Figure))
        End Function
        Public Function CompareTo(ByVal other As Figure) As Integer
            CompareTo = Me.GetArea().CompareTo(other.GetArea())
        End Function
        Public Overrides Function ToString() As String
            ToString = GetArea.ToString()
        End Function
    End Class
End Namespace

21.3.3. Het IComparable.CompareTo Contract

Er zijn enkele condities waaraan de implementatie van de CompareTo method aan moet voldoen :

- Een ArgumentException treedt op indien je een object van een bepaald type zou proberen te vergelijken via CompareTo met een object van een ongerelateerd type (1).

- Elke object is "groter" dan Nothing (2). <any-object>.CompareTo(Nothing) levert dus een positieve waarde op.

Method CompareTo van Figure moeten we dus als volgt verbeteren :
Visual Basic 2012 Broncode - Codevoorbeeld 463
Namespace Example5
    MustInherit Class Figure : Implements IComparable
        Public MustOverride Function GetArea() As Double
        Private Function CompareTo(ByVal obj As Object) As Integer _
                                         Implements System.IComparable.CompareTo
            If Not TypeOf obj Is Figure Then                               ' (1)
                Throw New ArgumentException("An invalid argument was " & _
                          "specified.  An argument of type Figure is required.")
            Else
                CompareTo = CompareTo(DirectCast(obj, Figure))
            End If
        End Function
        Public Function CompareTo(ByVal other As Figure) As Integer
            If other IsNot Nothing Then                                    ' (2)
                CompareTo = 1
            Else
                CompareTo = Me.GetArea().CompareTo(other.GetArea())
            End If
        End Function
        Public Overrides Function ToString() As String
            ToString = GetArea.ToString()
        End Function
    End Class
End Namespace
Andere afspraken in het contract van IComparable.CompareTo zijn :

- x.CompareTo(x) levert nul op.

- Als x.CompareTo(y) nul oplevert dan zou ook y.CompareTo(x) nul moeten opleveren.

- Als zowel x.CompareTo(y) als y.CompareTo(z) nul opleveren dan moet ook x.CompareTo(z) nul opleveren.

- Als x.CompareTo(y) een positieve waarde oplevert dan moet y.CompareTo(x) een negatieve waarde opleveren, en vice versa.

- Als x.CompareTo(y) en y.CompareTo(z) beide waardes opleveren met een bepaald teken (positief of negatief) dan moet ook x.CompareTo(z) een waarde opleveren met hetzelfde teken.

21.3.4. Oefeningen

Opgave :

Zorg ervoor dat in onderstaande code, een collectie van Counter objecten kan gesorteerd worden.  Of dus dat verschillende Counter objecten onderling met elkaar vergeleken kunnen worden.
Visual Basic 2012 Broncode - Codevoorbeeld 464
Namespace Exercise1
    Class Counter
        Public Property Value As Integer
        Public Overrides Function ToString() As String
            ToString = Value.ToString()
        End Function
    End Class
    Class Client
        Public Shared Sub Main()
            Dim counter1 As Counter = New Counter With {.Value = 1}
            Dim counter2 As Counter = New Counter With {.Value = 2}
            '
            Dim countersArrayList1 As ArrayList = New ArrayList
            '
            countersArrayList1.Add(counter2)
            countersArrayList1.Add(counter1)
            Print(countersArrayList1)
            '
            countersArrayList1.Sort()
            Print(countersArrayList1)
            '
            Console.ReadLine()
        End Sub
        Public Shared Sub Print(ByVal arrayList As ArrayList)
            For Each element As Object In arrayList
                Console.Write(element.ToString() & " ")
            Next
            Console.WriteLine()
        End Sub
    End Class
End Namespace
Console Application Output
2 1
1 2
Oplossing :
Visual Basic 2012 Broncode - Codevoorbeeld 465
Namespace Exercise1
    Partial Class Counter : Implements IComparable
        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 Counter Then
                Throw New ArgumentException("An invalid argument was " & _
                         "specified.  An argument of type Counter is required.")
            Else
                CompareTo = Value.CompareTo(DirectCast(obj, Counter).Value)
            End If
        End Function
    End Class
End Namespace
Opgave :

Bestudeer onderstaande klasse Counter :
Visual Basic 2012 Broncode - Codevoorbeeld 466
Namespace Exercise2
    Class Counter : Implements IComparable
        Public Property Value As Integer
        Public Overrides Function ToString() As String
            ToString = Value.ToString()
        End Function
        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 Counter Then
                Throw New ArgumentException("An invalid argument was " & _
                         "specified.  An argument of type Counter is required.")
            Else
                CompareTo = Value.CompareTo(DirectCast(obj, Counter).Value)
            End If
        End Function
    End Class
End Namespace
Zoals onderstaande Test1CompareTo aangeeft kunnen verschillende objecten van deze klasse Counter kunnen onderling met elkaar vergeleken worden via de CompareTo implementatie uit de IComparable interface.
Visual Basic 2012 Broncode - Codevoorbeeld 467
Namespace Exercise2
    Class Client
        Private Shared counter1 As Counter = New Counter With {.Value = 1}
        Private Shared counter2 As Counter = New Counter With {.Value = 2}
        Public Shared Sub Test1CompareTo()
            Console.WriteLine("Test1CompareTo :")
            '
            Console.WriteLine(counter1.CompareTo(counter1))
            Console.WriteLine(counter1.CompareTo(counter2))
            Console.WriteLine(counter2.CompareTo(counter1))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Test1CompareTo :

0
-1
1
Wat echter ook mogelijk is (door de compiler wordt toegelaten), en wat onderstaande Test2CompareTo ook aangeeft, is dat eender welk ander object vergeleken wordt met een Counter object.
De CompareTo implementatie uit Counter werkt hier immers met een Object argument, wat maakt dat argumentwaarden van eender welk datatype aan deze CompareTo method kunnen worden doorgegeven.
Visual Basic 2012 Broncode - Codevoorbeeld 468
Namespace Exercise2
    Partial Class Client
        Public Shared Sub Test2CompareTo()
            Console.WriteLine("Test2CompareTo :")
            '
            Console.WriteLine(counter1.CompareTo("dummy"))
        End Sub
        Public Shared Sub Main()
            Test1CompareTo()
            Test2CompareTo()
        End Sub
    End Class
End Namespace
Bovenstaande Test2CompareTo zal at runtime een fout geven.  De aan de CompareTo doorgegeven String is immers niet van type Counter.

Pas bovenstaande klasse Counter zo aan dat reeds at compiletime het foutieve gebruik zoals in Test2CompareTo verhinderd wordt.  Met foutief gebruik wordt hier dus bedoeld : het doorgeven van een niet Counter object aan de de CompareTo implementatie.
Zorg er echter wel voor dat verschillende Counter objecten, zoals in Test1CompareTo wel nog met elkaar vergeleken kunnen worden.

Oplossing :
Visual Basic 2012 Broncode - Codevoorbeeld 469
Namespace Exercise2Solution
    Class Counter : Implements IComparable
        Public Property Value As Integer
        Public Overrides Function ToString() As String
            ToString = Value.ToString()
        End Function
        Private Function CompareTo(ByVal obj As Object) As Integer _
                                         Implements System.IComparable.CompareTo
            If Not TypeOf obj Is Counter Then
                Throw New ArgumentException("An invalid argument was " & _
                         "specified.  An argument of type Counter is required.")
            Else
                CompareTo = CompareTo(DirectCast(obj, Counter))
            End If
        End Function
        Public Function CompareTo(ByVal other As Counter) As Integer
            If other IsNot Nothing Then
                CompareTo = 1
            Else
                CompareTo = Me.Value.CompareTo(other.Value)
            End If
        End Function
    End Class
    Class Client
        Private Shared counter1 As Counter = New Counter With {.Value = 1}
        Private Shared counter2 As Counter = New Counter With {.Value = 2}
        Public Shared Sub Test1CompareTo()
            Console.WriteLine("Test1CompareTo :")
            '
            Console.WriteLine(counter1.CompareTo(counter1))
            Console.WriteLine(counter1.CompareTo(counter2))
            Console.WriteLine(counter2.CompareTo(counter1))
            '
            Console.ReadLine()
        End Sub
        Public Shared Sub Test2CompareTo()
            Console.WriteLine("Test2CompareTo :")
            '
            'Console.WriteLine(counter1.CompareTo("dummy")) ' compile error
            '
            Console.ReadLine()
        End Sub
        Public Shared Sub Main()
            Test1CompareTo()
            Test2CompareTo()
        End Sub
    End Class
End Namespace
Console Application Output
Test1CompareTo :

0
-1
1
Opgave :

Creëer een Reservation klasse met een StartDate en EndDate eigenschap.

Een array van objecten van het type Reservation zou sorteerbaar moeten zijn met de Array.Sort method.

Reservaties moeten gesorteerd worden eerst oplopend (van oud naar nieuw) volgens startdatum, is deze gelijk dan oplopend (van oud naar nieuw) volgens einddatum.

Oplossing :
Visual Basic 2012 Broncode - Codevoorbeeld 470
Namespace Exercise3
    Public Class Reservation : Implements IComparable
        Public Sub New(ByVal startDate As Date, ByVal endDate As Date)
            Me.StartDate = startDate
            Me.EndDate = endDate
        End Sub
        Public Property StartDate As Date
        Public Property EndDate As Date
        Public Overrides Function ToString() As String
            ToString = StartDate.ToShortDateString() & "-" & _
                       EndDate.ToShortDateString()
        End Function
        Private Function CompareTo(ByVal obj As Object) As Integer _
                                 Implements System.IComparable.CompareTo
            If Not TypeOf obj Is Reservation Then
                Throw New ArgumentException("An invalid argument was " & _
                     "specified.  An argument of type Reservation is required.")
            Else
                CompareTo = CompareTo(DirectCast(obj, Reservation))
            End If
        End Function
        Public Function CompareTo(ByVal other As Reservation) As Integer
            If other IsNot Nothing Then
                CompareTo = 1
            Else
                CompareTo = Me.StartDate.CompareTo(other.StartDate)
                If CompareTo = 0 Then
                    CompareTo = Me.EndDate.CompareTo(other.EndDate)
                End If
            End If
        End Function
    End Class
    Public Class Client
        Public Shared Sub Main()
            Dim reservations1 As Reservation() = New Reservation() _
                                     {New Reservation(#4/1/2008#, #4/8/2008#), _
                                      New Reservation(#4/1/2008#, #4/5/2008#), _
                                      New Reservation(#3/30/2008#, #3/31/2008#)}
            '
            Console.WriteLine("Unsorted :")
            For Each element As Reservation In reservations1
                Console.WriteLine(element)
            Next
            Console.WriteLine()
            '
            Array.Sort(reservations1)
            '
            Console.WriteLine("Sorted :")
            For Each element As Reservation In reservations1
                Console.WriteLine(element)
            Next
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Unsorted :
1/04/2008-8/04/2008
1/04/2008-5/04/2008
30/03/2008-31/03/2008

Sorted :
30/03/2008-31/03/2008
1/04/2008-5/04/2008
1/04/2008-8/04/2008
Opgave :

Maak een systeem waarbij verschillende soorten "calculations" ( "berekeningen") kunnen worden gemaakt, voorzie minimaal de mogelijkheid om een "division" ("deling") en een "multiplication" ( "vermenigvuldiging") te creëren.

Alle berekeningen hebben gemeenschappelijk dat ze een bepaald resultaat ( "quotient", "product", ...) kunnen opleveren en dat ze herhaald kunnen worden ("divide by", "multiply by", ...).

Onderstaande clientcode illustreert wat onder andere mogelijk moet zijn.
Visual Basic 2012 Broncode - Codevoorbeeld 471
Namespace Exercise4
    Class Client
        Public Shared Sub Main()
            Dim division1 As Division = New Division(20, 5)
            Dim division2 As Division = New Division(10, 5)
            '
            Console.WriteLine(division1.Quotient())
            Console.WriteLine(division1.DivideBy(division2))
            '
            Dim multiplication1 As Multiplication = New Multiplication(2, 3)
            Console.WriteLine(multiplication1.Product())
            Console.WriteLine(multiplication1.MultiplyBy(division2))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
4
2
6
12
Oplossing :
Visual Basic 2012 Broncode - Codevoorbeeld 472
Namespace Exercise4
    Interface ICalculation
        Function GetResult() As Decimal
        Function Repeat(ByVal other As ICalculation) As Double
    End Interface
    Class Multiplication : Implements ICalculation
        Public Sub New(ByVal operand1 As Double, ByVal operand2 As Double)
            Me.Operand1 = operand1
            Me.operand2 = operand2
        End Sub
        Public Property Operand1 As Double
        Public Property Operand2 As Double
        Function Product() As Decimal Implements ICalculation.GetResult
            Product = Convert.ToDecimal(Operand1 * Operand2)
        End Function
        Public Function MultiplyBy(ByVal other As ICalculation) As Double _
                                                  Implements ICalculation.Repeat
            MultiplyBy = Product() * other.GetResult()
        End Function
    End Class
    Class Division : Implements ICalculation
        Public Sub New(ByVal dividend As Double, ByVal divisor As Double)
            Me.Dividend = dividend
            Me.Divisor = divisor
        End Sub
        Public Property Dividend As Double
        Public Property Divisor As Double
        Function Quotient() As Decimal Implements ICalculation.GetResult
            Quotient = Convert.ToDecimal(Dividend / Divisor)
        End Function
        Public Function DivideBy(ByVal other As ICalculation) As Double _
                                                  Implements ICalculation.Repeat
            DivideBy = Quotient() / other.GetResult()
        End Function
    End Class
End Namespace

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