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.

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 :

  1: Public Enum File
  2:     FileA
  3:     FileB
  4:     ' ...
  5: End Enum
  6: Public Enum Rank
  7:     Rank1
  8:     Rank2
  9:     ' ...
 10: End Enum
 11: Namespace Example1
 12:     Public Class Square
 13:         Public Sub New(ByVal file As File, ByVal rank As Rank)
 14:             _File = file
 15:             _Rank = rank
 16:         End Sub
 17:         Private ReadOnly _File As File
 18:         Public ReadOnly Property File() As File
 19:             Get
 20:                 File = _File
 21:             End Get
 22:         End Property
 23:         Private ReadOnly _Rank As Rank
 24:         Public ReadOnly Property Rank() As Rank
 25:             Get
 26:                 Rank = _Rank
 27:             End Get
 28:         End Property
 29:     End Class
 30:     Class Client
 31:         Public Shared Sub Main()
 32:             Dim square1 As New Square(File.FileA, Rank.Rank1)
 33:             Dim square2 As New Square(File.FileB, Rank.Rank1)
 34:             '
 35:             Dim board As New Hashtable
 36:             board.Add(square1, "R")
 37:             board.Add(square2, "K")
 38:             '
 39:             Console.WriteLine(board.Item(square1).ToString()) ' R
 40:             Console.WriteLine(board.Item(square2).ToString()) ' K
 41:             '
 42:             Console.ReadLine()
 43:         End Sub
 44:     End Class
 45: End Namespace
 46: 
 47: 

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.

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 :

  1: Namespace Example2
  2:     Class Client
  3:         Public Shared Sub Main()
  4:             Dim square1 As New Example1.Square(File.FileA, Rank.Rank1)     ' (1)
  5:             Dim square2 As New Example1.Square(File.FileB, Rank.Rank1)
  6:             Dim square3 As New Example1.Square(File.FileA, Rank.Rank1)     ' (2)
  7:             '
  8:             Dim board As New Hashtable
  9:             board.Add(square1, "R")
 10:             board.Add(square2, "K")
 11:             '
 12:             Console.WriteLine(board.Item(square1).ToString()) ' R
 13:             Console.WriteLine(board.Item(square2).ToString()) ' K
 14:             Console.WriteLine(board.Item(square3) Is Nothing) ' True         (3)
 15:             '
 16:             Console.ReadLine()
 17:         End Sub
 18:     End Class
 19: End Namespace

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 :

  1: Namespace Example2
  2:     Class TestEqualityAndHashCode
  3:         Public Shared Sub Main()
  4:             Dim square1 As New Example1.Square(File.FileA, Rank.Rank1)
  5:             Dim square3 As New Example1.Square(File.FileA, Rank.Rank1)
  6:             '
  7:             Console.WriteLine(square1.Equals(square3))                   ' False
  8:             Console.Write(square1.GetHashCode() = square3.GetHashCode()) ' False
  9:             '
 10:             Console.ReadLine()
 11:         End Sub
 12:     End Class
 13: End Namespace

De van Object overgeërfde GetHashCode zal zich voor de op te leveren hash code baseren op de fysieke identiteit.

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.

  1: Namespace Example3
  2:     Class Square
  3:         Public Sub New(ByVal file As File, ByVal rank As Rank)
  4:             _File = file
  5:             _Rank = rank
  6:         End Sub
  7:         Private ReadOnly _File As File
  8:         Public ReadOnly Property File() As File
  9:             Get
 10:                 File = _File
 11:             End Get
 12:         End Property
 13:         Private ReadOnly _Rank As Rank
 14:         Public ReadOnly Property Rank() As Rank
 15:             Get
 16:                 Rank = _Rank
 17:             End Get
 18:         End Property
 19:     End Class
 20: 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 :

  1: Namespace Example3
  2:     Partial Class Square
  3:         Public Overrides Function Equals(ByVal obj As Object) As Boolean
  4:             If obj IsNot Nothing AndAlso TypeOf obj Is Square Then
  5:                 Dim other As Square = DirectCast(obj, Square)
  6:                 Equals = (Me.Rank = other.Rank AndAlso Me.File = other.File)
  7:             End If
  8:         End Function
  9:     End Class
 10:     Public Class TestEquality
 11:         Public Shared Sub Main()
 12:             Dim square1 As New Square(File.FileA, Rank.Rank1)
 13:             Dim square3 As New Square(File.FileA, Rank.Rank1)
 14:             '
 15:             Console.Write(square1.Equals(square3)) ' True
 16:             '
 17:             Console.ReadLine()
 18:         End Sub
 19:     End Class
 20: End Namespace

Bron : vbvoorbeelden.be