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

13.4. Logische Gelijkheid - Equals

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.

13.4.1. Logisch Gelijkheid tussen Value Types

Naast fysieke gelijkheid bestaat er ook nog zoiets als logische gelijkheid.  De logica die gebruikt wordt om na te gaan of twee objecten logisch gelijk zijn is per type te bepalen.

Voor een aantal datatypes kan men de = vergelijkingsoperator gebruiken om logische gelijkheid na te gaan.  Dit geldt voor de valuetypes, maar ook voor sommige ingebouwde referencetypes.
Zo kan men bijvoorbeeld twee String objecten met de = operator op logische gelijkheid testen, bijvoorbeeld "abc" = "abc".

"Operator overloading" zou kunnen worden toegepast voor de datatypes die deze operator (of andere operatoren) niet ondersteunen, hierover in een later topic meer.
Visual Basic 2012 Broncode - Codevoorbeeld 353
Option Strict On
Option Explicit On
Namespace Example1
    Class Client
        Public Shared Sub Main()
            Console.WriteLine(1 = 2)              ' False
            Console.WriteLine(1 <> 2)             ' True
            '
            Dim string1 As New String(New Char() {"a"c, "b"c, "c"c})
            Dim string2 As New String(New Char() {"a"c, "b"c, "c"c})
            ' physically different objects :
            Console.WriteLine(string1 Is string2) ' False
            ' logically equal objects :
            Console.WriteLine(string1 = string2)  ' True
            Console.WriteLine(string1 <> string2) ' False
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True
True
False
Operator <> kan gebruikt worden om na te gaan of er een verschil is tussen de twee operanden.  Waarbij verschil betekent dat ze logisch gezien niet gelijk zijn aan elkaar.
Elke datatype van expressies waarmee men via de = operator gelijkheid kan nagaan, ondersteunt ook de <> operator.  Zie verderop voor meer informatie over operator overloading.

13.4.2. Equals Method

Alle valuetypes erven van de System.ValueType een Equals(obj As Object) As Boolean functie over.

Ook deze is bruikbaar om logisch gelijkheid na te gaan :
Visual Basic 2012 Broncode - Codevoorbeeld 354
Namespace Example2
    Class Client
        Public Shared Sub Main()
            Console.WriteLine(1.Equals(2))
            '
            Dim string1 As New String(New Char() {"a"c, "b"c, "c"c})
            Dim string2 As New String(New Char() {"a"c, "b"c, "c"c})
            Console.WriteLine(string1.Equals(string2))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True
Ook op onze user-defined valuetypes kunnen we deze Equals method gebruiken.

Het gedrag die wordt overgeërfd (van System.ValueType) zal de volledige toestand (de verzameling van alle velden) van de instanties vergelijken.

Slechts indien de X en Y waarde van twee Coordinate instanties gelijk zijn, zullen deze twee instanties als logisch gelijk worden beschouwd :
Visual Basic 2012 Broncode - Codevoorbeeld 355
Namespace Example3
    Structure Coordinate
        Public Sub New(ByVal x As Integer, ByVal y As Integer)
            Me.X = x
            Me.Y = y
        End Sub
        Public Property X As Integer
        Public Property Y As Integer
    End Structure
    Class Client1
        Public Shared Sub Main()
            Dim coordinate1 As New Coordinate(1, 2)
            Dim coordinate2 As New Coordinate(1, 3)
            Dim coordinate3 As New Coordinate(1, 2)
            '
            Console.WriteLine(coordinate1.Equals(coordinate2))
            Console.WriteLine(coordinate1.Equals(coordinate3))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True
Het was met bovenstaande Coordinate niet mogelijk om twee instanties van deze structure te gaan vergelijken met de = of <> operatoren.

Hier is het gebruik van de Equals method dus noodzakelijk indien we logische gelijkheid wensen na te gaan.

De Equals method die elke valuetype overerft, is Overridable gedefinieerd.  Dit maakt het mogelijk om het gedrag, of dus de manier waarop logische gelijkheid wordt bepaald, aan te passen door deze method te gaan overschrijven :
Visual Basic 2012 Broncode - Codevoorbeeld 356
Namespace Example4
    Structure Coordinate
        Public Sub New(ByVal x As Integer, ByVal y As Integer)
            Me.X = x
            Me.Y = y
        End Sub
        Public Property X As Integer
        Public Property Y As Integer
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj IsNot Nothing AndAlso TypeOf obj Is Coordinate Then
                Equals = (Me.X = DirectCast(obj, Coordinate).X)
            End If
        End Function
    End Structure
End Namespace
In bovenstaande versie van Coordinate is vastgelegd dat twee instanties logisch gezien gelijk zijn aan elkaar indien ze dezelfde X waarde hebben.

Onderstaande client zal nu alle Coordinate instanties als logisch gelijk beschouwen omdat ze dezelfde X waarde hebben :
Visual Basic 2012 Broncode - Codevoorbeeld 357
Namespace Example4
    Class Client
        Public Shared Sub Main()
            Dim coordinate1 As New Coordinate(1, 2)
            Dim coordinate2 As New Coordinate(1, 3)
            Dim coordinate3 As New Coordinate(1, 2)
            '
            Console.WriteLine(coordinate1.Equals(coordinate2))
            Console.WriteLine(coordinate1.Equals(coordinate3))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
True
True
De implementatie van bovenstaande Equals method, namelijk : Equals = (Me.X = DirectCast(obj, Coordinate).X)
kunnen we ook schrijven als : Equals = Me.X.Equals(DirectCast(obj, Coordinate).X).

De X property van het type Integer heeft immers ook de Equals method, bruikbaar om twee Integer instanties met elkaar te vergelijken.

13.4.3. Logische Gelijkheid tussen Reference Types

Logische gelijkheid is minder éénduidig dan fysieke gelijkheid, waarop logische gelijkheid wordt gebaseerd is afhankelijk van het type van de vergeleken objecten.

Men zou bijvoorbeeld twee Person objecten logische gelijk kunnen beschouwen als ze dezelfde naam hebben.  Of twee Addition objecten kunnen beschouwen als logisch gelijk wanneer ze hetzelfde resultaat hebben.

Van het type System.Object erft iedere referencetype een Equals(obj As Object) As Boolean functie over.  Het is trouwens deze die door System.ValueType wordt overgeërfd en geherdefinieerd.

De implementatie die echter door de referencetypes (rechtstreeks) van System.Object wordt overgeërfd zal de referenties (net als de Is operator of de ReferenceEquals method) gaan vergelijken.
By default gaat het dus om fysieke gelijkheid die door deze implemenatie wordt nagegaan :
Visual Basic 2012 Broncode - Codevoorbeeld 358
Namespace Example5
    Class Person
        Public Property Name As String
    End Class
    Class Client
        Public Shared Sub Main()
            Dim person1 As New Person With {.Name = "John"}
            Dim person2 As New Person With {.Name = "John"}
            Dim person3 As Person = person1
            '
            Console.WriteLine(person1.Equals(person2))
            Console.WriteLine(person1.Equals(person3))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True
Zoals we reeds gezien hebben is deze Equals method echter wel Overridable, wat maakt dat we het gedrag van deze kunnen herdefiniëren, en zelf kunnen uitkiezen waarop logische gelijkheid tussen twee instanties van ons type kan worden gebaseerd.

Twee Additon objecten zouden we bijvoorbeeld als logisch gelijk kunnen beschouwen indien ze hetzelfde resultaat (GetResult()) hebben :
Visual Basic 2012 Broncode - Codevoorbeeld 359
Namespace Example6
    Class Addition
        Public Property Operand1 As Integer
        Public Property Operand2 As Integer
        Public Function GetResult() As Integer
            GetResult = Operand1 + Operand2
        End Function
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj IsNot Nothing AndAlso TypeOf obj Is Addition Then
                Equals = _
                       GetResult().Equals(DirectCast(obj, Addition).GetResult())
            End If
        End Function
    End Class
    Class Client1
        Public Shared Sub Main()
            Dim addition1 As New Addition With {.Operand1 = 2, .Operand2 = 3}
            Dim addition2 As New Addition With {.Operand1 = 2, .Operand2 = 4}
            Dim addition3 As New Addition With {.Operand1 = 4, .Operand2 = 1}
            '
            Console.WriteLine(addition1.Equals(addition2))
            Console.WriteLine(addition1.Equals(addition3))
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True

13.4.4. Hoe de Equals Method Implementeren

Als x, y en z object expressies zijn, verschillend van Nothing, dan moet het volgende gelden :

- x.Equals(x) is True (reflexief)
- x.Equals(y) levert hetzelfde op als y.Equals(x) (symmetrisch)
- als x.Equals(y) en y.Equals(z) True zijn dan is ook x.Equals(z) True (transitief)
- zolang de toestand van x en y ongewijzigd blijven, zullen herhaaldelijke calls naar x.Equals(y) hetzelfde resultaat opleveren ( consistent)
- x.Equals(Nothing) levert False op

De implementatie van de Equals method mag geen exceptie opgooien.

Datatypes die de IComparable interface implementeren moeten Equals herdefiniëren.
Zie het topic over IComparable voor meer details over deze interface.

Indien de Equals method door een type overschreven wordt, moet dit type eigenlijk ook de van Object overgeërfde GetHashCode() method overschrijven.
Zie het topic over Dictionaries, HashTable en GetHashCode voor meer details.

13.4.5. Equals Symmetrie en Inheritance

Stel dat twee Counter objecten als logisch gelijk worden beschouwd indien ze dezelfde Value bevatten en twee StepCounter objecten als logisch gelijk worden beschouwd indien ze dezelfde Value en StepValue bevatten.

Dan druist onderstaande implementatie van de Equals method in Counter in tegen het symmetrie principe :
Visual Basic 2012 Broncode - Codevoorbeeld 360
Namespace NoSymmetry
    Class Client
        Public Shared Sub Main()
            Dim counter1 As Counter = New Counter
            Dim counter2 As Counter = New Counter
            Console.WriteLine(counter1.Equals(counter2)) ' True
            Console.WriteLine(counter2.Equals(counter1)) ' True
            '
            Dim counter3 As Counter = New StepCounter
            Console.WriteLine(counter1.Equals(counter3)) ' (1) True
            Console.WriteLine(counter3.Equals(counter1)) ' (2) False
            '
            Console.ReadLine()
        End Sub
    End Class
    Class Counter
        Protected _Value As Integer
        Public ReadOnly Property Value() As Integer
            Get
                Value = _Value
            End Get
        End Property
        Public Overridable Sub Raise()
            _Value += 1
        End Sub
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj IsNot Nothing AndAlso _
               TypeOf obj Is Counter Then
                Equals = Value.Equals(DirectCast(obj, Counter).Value)
            End If
        End Function
    End Class
    Class StepCounter : Inherits Counter
        Public Property StepValue As Integer
        Public Overrides Sub Raise()
            _Value += StepValue
        End Sub
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj IsNot Nothing AndAlso _
               TypeOf obj Is StepCounter Then                              ' (3)
                Equals = _
                      Value.Equals(DirectCast(obj, StepCounter).Value) AndAlso _
                      StepValue.Equals(DirectCast(obj, StepCounter).StepValue)
            End If
        End Function
    End Class
End Namespace
Console Application Output
True
True
True
False
Indien counter1.Equals(counter3) True is dan zou ook counter3.Equals(counter1) True moeten zijn, wat niet het geval is, zoals je ziet aan bovenstaande regels (1) en (2).

De oorzaak zit hem op regel (3), de call naar counter3.Equals(counter1) zal False opleveren gezien het argument (counter1 niet van type StepCounter is.
Beide (counter1 en counter3) zijn geen StepCounters maar ze zijn wel beide Counters.  Hier zou dus de logica voor logische gelijkheid moeten gelden waarbij enkel gekeken wordt naar de Value en niet naar de StepValue.  Of met andere woorden de logische gelijkheids logica van Counter.

We zouden dit kunnen oplossen door in de implementatie van StepCounter na te gaan of het argument van een basistype is, en zoja ook naar de logica van de basisklasse te verwijzen (zie onderstaand regel (3)) :
Visual Basic 2012 Broncode - Codevoorbeeld 361
Namespace Symmetry
    Class Client
        Public Shared Sub Main()
            Dim counter1 As NoSymmetry.Counter = New NoSymmetry.Counter
            Dim counter2 As NoSymmetry.Counter = New NoSymmetry.Counter
            Console.WriteLine(counter1.Equals(counter2)) ' True
            Console.WriteLine(counter2.Equals(counter1)) ' True
            '
            Dim counter3 As NoSymmetry.Counter = New StepCounter
            Console.WriteLine(counter1.Equals(counter3)) ' (1) True
            Console.WriteLine(counter3.Equals(counter1)) ' (2) True
            '
            Console.ReadLine()
        End Sub
    End Class
    Class StepCounter : Inherits NoSymmetry.Counter
        Public Property StepValue As Integer
        Public Overrides Sub Raise()
            _Value += StepValue
        End Sub
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj IsNot Nothing Then
                If Me.GetType().IsSubclassOf(obj.GetType()) Then           ' (3)
                    Equals = MyBase.Equals(obj)
                ElseIf TypeOf obj Is StepCounter Then
                    Equals = _
                      Value.Equals(DirectCast(obj, StepCounter).Value) AndAlso _
                      StepValue.Equals(DirectCast(obj, StepCounter).StepValue)
                End If
            End If
        End Function
    End Class
End Namespace
Console Application Output
True
True
True
True
Bemerk op regel (1) en (2) hoe het symmetrie principe nu wel geldt, counter1.Equals(counter3) levert hetzelfde op als counter3.Equals(counter1).

13.4.6. Operator Overloading

Indien men het mogelijk wil maken bepaalde operatoren, als = en <> ook te kunnen gebruiken op instanties van user-defined types, kan men "operator overloading" toepassing :
Visual Basic 2012 Broncode - Codevoorbeeld 362
Namespace Example3
    Partial Structure Coordinate
        Public Shared Operator =(ByVal coordinate1 As Coordinate, _
                                 ByVal coordinate2 As Coordinate) As Boolean
            Return coordinate1.Equals(coordinate2)
        End Operator
        Public Shared Operator <>(ByVal coordinate1 As Coordinate, _
                                  ByVal coordinate2 As Coordinate) As Boolean
            Return Not coordinate1.Equals(coordinate2)
        End Operator
    End Structure
    Class Client2
        Public Shared Sub Main()
            Dim coordinate1 As New Coordinate(1, 2)
            Dim coordinate2 As New Coordinate(1, 3)
            Dim coordinate3 As New Coordinate(1, 2)
            '
            Console.WriteLine(coordinate1 = coordinate2)
            Console.WriteLine(coordinate1 <> coordinate2)
            Console.WriteLine(coordinate1 = coordinate3)
            Console.WriteLine(coordinate1 <> coordinate3)
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True
True
False
Ook voor referencetypes is dit mogelijk :
Visual Basic 2012 Broncode - Codevoorbeeld 363
Namespace Example6
    Partial Class Addition
        Public Shared Operator =(ByVal addition1 As Addition, _
                                 ByVal addition2 As Addition) As Boolean
            Return addition1.Equals(addition2)
        End Operator
        Public Shared Operator <>(ByVal addition1 As Addition, _
                                  ByVal addition2 As Addition) As Boolean
            Return Not addition1.Equals(addition2)
        End Operator
    End Class
    Class Client2
        Public Shared Sub Main()
            Dim addition1 As New Addition With {.Operand1 = 2, .Operand2 = 3}
            Dim addition2 As New Addition With {.Operand1 = 2, .Operand2 = 4}
            Dim addition3 As New Addition With {.Operand1 = 4, .Operand2 = 1}
            '
            Console.WriteLine(addition1 = addition2)
            Console.WriteLine(addition1 <> addition2)
            Console.WriteLine(addition1 = addition3)
            Console.WriteLine(addition1 <> addition3)
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
True
True
False
Indien een type de operatoren = en <> overladen worden, moet ook Equals door dit type geherdefinieerd worden.

Voor meer details kan je terecht bij het topic over operator overloading.

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