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.13. Hashtable - Equals en GetHashCode

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.13.1. Hashtable

Een Hashtable is specifiek ontworpen om efficient/snel elementen te kunnen toevoegen, verwijderen en opzoeken.

Het werkt door de op te zoeken key of de key van de toe te voegen entry via een hash functie om te zetten naar een hash code/waarde.  Daarvoor gebruikt deze de van Object overgeërfde GetHashCode() method van het keytype.
De door GetHashCode opgeleverde hash waarde is een getal die aangeeft op welke locatie (ook wel bucket genoemd) de entry wordt bewaard of wordt opgezocht.  Dit getal (key omgezet in hash code) is een index van een tabel met buckets voor alle hash codes.

Als de hash function performant is, wat steeds de bedoeling is, kan het vinden of toevoegen van een element erg snel/efficient gebeuren.

22.13.2. Indien Fysieke Ook Logische Gelijkheid Is

Stel dat we van vak (Square) op een schaakbord (board As HashTable) wensen te weten welke stuk (String) zich op dit vak bevindt.
We kunnen hiervoor de Square objecten mappen met de stukken door een HashTable te gebruiken.  De Square objecten zijn de keys, de stukken zijn de values :
Visual Basic 2012 Broncode - Codevoorbeeld 551
Public Enum File
    FileA
    FileB
    ' ...
End Enum
Public Enum Rank
    Rank1
    Rank2
    ' ...
End Enum
Namespace Example1
    Public Class Square
        Public Sub New(ByVal file As File, ByVal rank As Rank)
            _File = file
            _Rank = rank
        End Sub
        Private ReadOnly _File As File
        Public ReadOnly Property File() As File
            Get
                File = _File
            End Get
        End Property
        Private ReadOnly _Rank As Rank
        Public ReadOnly Property Rank() As Rank
            Get
                Rank = _Rank
            End Get
        End Property
    End Class
    Class Client
        Public Shared Sub Main()
            Dim square1 As New Square(File.FileA, Rank.Rank1)
            Dim square2 As New Square(File.FileB, Rank.Rank1)
            '
            Dim board As New Hashtable
            board.Add(square1, "R")
            board.Add(square2, "K")
            '
            Console.WriteLine(board.Item(square1).ToString()) ' R
            Console.WriteLine(board.Item(square2).ToString()) ' K
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
R
K
Bovenstaande werkwijze functioneert goed indien elk vak op het bord slecht door één Square object wordt voorgesteld.
Vergeet ook niet dat een Hashtable gebruik maakt van de hash code van het keyobject om de entry te kunnen plaatsen of opzoeken.  Square erft van Object een GetHashCode over waarvan de opgeleverde hash code gebaseerd wordt op de referentie van het desbetreffende object.
De Hashtable (hier board) maakt gebruik van deze hashcode om een Square object te plaatsen (via Add) of op te zoeken (bijvoorbeeld via Item) in de collectie.

22.13.3. Indien Logische Geen Fysieke Gelijkheid Is

Indien er echter verschillende objecten zijn die hetzelfde vak voorstellen ((1) en (2)), zijn ze in dat opzicht logisch gelijk, volstaat bovenstaande constructie niet.

Voor meer informatie over fysieke versus logisch gelijkheid kan je terecht in de desbetreffende topics.

In onderstaand voorbeeld verwijzen zowel square1 als square3 naar vak "A1".
De expressie board.Item(square3) die ons zou moeten opleveren welk stuk zich bevindt op vak "A1" levert echter niets (Nothing) op :
Visual Basic 2012 Broncode - Codevoorbeeld 552
Namespace Example2
    Class Client
        Public Shared Sub Main()
            Dim square1 As New Example1.Square(File.FileA, Rank.Rank1)     ' (1)
            Dim square2 As New Example1.Square(File.FileB, Rank.Rank1)
            Dim square3 As New Example1.Square(File.FileA, Rank.Rank1)     ' (2)
            '
            Dim board As New Hashtable
            board.Add(square1, "R")
            board.Add(square2, "K")
            '
            Console.WriteLine(board.Item(square1).ToString()) ' R
            Console.WriteLine(board.Item(square2).ToString()) ' K
            Console.WriteLine(board.Item(square3) Is Nothing) ' True         (3)
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
R
K
True
Bovenstaand ongewenst resultaat mag op zich niet verwonderen.  square1 en square3 zijn immers fysiek verschillende objecten, met elke hun eigen hash code.  En het is deze hash code die de Hashtable gebruikt om de objecten te identificeren (plaatsen en opzoeken).  Als de Hashtable niet weet dat we ook via square3 stuk "R" wensen te vinden, of met andere woorden square1 en square3 logisch gelijk zijn, kan deze ook niet het gewenste verdrag vertonen.
De Hashtable baseert zich op de hashcode van de keyobjecten om deze te identificeren (en dus te vergelijken), en deze zijn van onze twee objecten square1 en square3 nu immers verschillend :
Visual Basic 2012 Broncode - Codevoorbeeld 553
Namespace Example2
    Class TestEqualityAndHashCode
        Public Shared Sub Main()
            Dim square1 As New Example1.Square(File.FileA, Rank.Rank1)
            Dim square3 As New Example1.Square(File.FileA, Rank.Rank1)
            '
            Console.WriteLine(square1.Equals(square3))                   ' False
            Console.Write(square1.GetHashCode() = square3.GetHashCode()) ' False
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
False
De van Object overgeërfde GetHashCode zal zich voor de op te leveren hash code baseren op de fysieke identiteit.

22.13.4. Object.Equals Method

Over het algemeen gesteld is het zo dat, indien logische gelijkheid van het keytype niet correspondeert met fysieke gelijkheid, er extra vereisten zijn voor dat keytype.
We moeten door middel van de Equals implementatie aangeven welke objecten van dit keytype als logisch gelijk worden beschouwd, en door middel van de GetHashCode implementatie ervoor zorgen dat als logisch gelijk beschouwde objecten dan ook dezelfde hash code opleveren.

Aan onderstaand Square type moeten we dus enkel zaken toevoegen.
Visual Basic 2012 Broncode - Codevoorbeeld 554
Namespace Example3
    Class Square
        Public Sub New(ByVal file As File, ByVal rank As Rank)
            _File = file
            _Rank = rank
        End Sub
        Private ReadOnly _File As File
        Public ReadOnly Property File() As File
            Get
                File = _File
            End Get
        End Property
        Private ReadOnly _Rank As Rank
        Public ReadOnly Property Rank() As Rank
            Get
                Rank = _Rank
            End Get
        End Property
    End Class
End Namespace
Om logische gelijkheid te definiëren kunnen we de van Object overgeërfde Equals implementatie herdefiniëren.

In dit geval beschouwen we twee Square objecten als logisch gelijk indien ze beide naar hetzelfde vak verwijzen, of beide dus dezelfde File en Rank waarde delen :
Visual Basic 2012 Broncode - Codevoorbeeld 555
Namespace Example3
    Partial Class Square
        Public Overrides Function Equals(ByVal obj As Object) As Boolean
            If obj IsNot Nothing AndAlso TypeOf obj Is Square Then
                Dim other As Square = DirectCast(obj, Square)
                Equals = (Me.Rank = other.Rank AndAlso Me.File = other.File)
            End If
        End Function
    End Class
    Public Class TestEquality
        Public Shared Sub Main()
            Dim square1 As New Square(File.FileA, Rank.Rank1)
            Dim square3 As New Square(File.FileA, Rank.Rank1)
            '
            Console.Write(square1.Equals(square3)) ' True
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
True

22.13.5. Object.GetHashCode Method

Om er dan ook nog voor te zorgen dat Square objecten als key kunnen worden gebruikt, moeten we ook de van Object overgeërfde GetHashCode implementatie herdefiniëren.

Het belangrijkste voor deze implementatie is ervoor te zorgen dat logisch gelijke objecten steeds dezelfde hash code opleveren.  Logischerwijs zal je GetHashCode implementatie hiervoor van dezelfde aspecten/properties/velden gebruik maken als je Equals implementatie, al is dit geen technische vereiste.

We zouden bijvoorbeeld in dit geval File en Rank kunnen combineren via de Xor operator :
Visual Basic 2012 Broncode - Codevoorbeeld 556
Namespace Example3
    Partial Class Square
        Public Overrides Function GetHashCode() As Integer
            GetHashCode = File Xor Rank
        End Function
    End Class
    Public Class TestHashCode
        Public Shared Sub Main()
            Dim square1 As New Square(File.FileA, Rank.Rank1)
            Dim square3 As New Square(File.FileA, Rank.Rank1)
            '
            Console.Write(square1.GetHashCode() = square3.GetHashCode()) ' True
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
True
Waarom in dergelijke situatie vaak de Xor operator wordt gebruikt, wordt verderop behandeld.  Alvast is duidelijk dat twee objecten met dezelfde File en Rank waarde nu ook dezelfde hash code zullen opleveren, wat uiteindelijk hetgene is wat de GetHashCode moet doen.

Nu kunnen we wel aan de hand van square3, net als aan de hand van square1 het stuk "R" terugvinden :
Visual Basic 2012 Broncode - Codevoorbeeld 557
Namespace Example3
    Class Client
        Public Shared Sub Main()
            Dim square1 As New Square(File.FileA, Rank.Rank1)
            Dim square2 As New Square(File.FileB, Rank.Rank1)
            Dim square3 As New Square(File.FileA, Rank.Rank1)
            '
            Dim board As New Hashtable
            board.Add(square1, "R")
            board.Add(square2, "K")
            '
            Console.WriteLine(board.Item(square1).ToString()) ' R
            Console.WriteLine(board.Item(square2).ToString()) ' K
            Console.WriteLine(board.Item(square3).ToString()) ' R
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
R
K
R

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