Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a comparable Dictionary Key

I want to use a Dictionary(Of Key, Value), and the Key is not a base type, but a class like:

Public Class MyKey

    Sub New(ByVal packet As String, ByVal sent As Boolean)
        Me.packet = packet.ToUpper.Trim
        Me.sent = sent
    End Sub

    Private packet As String
    Private sent As Boolean
End Class

Now to have the Dictionary work and find the keys, I have to implement the System.IEquatable interface in the Key class (or use a different constructor, but that's another story):

Public Class MyKey
    Implements System.IEquatable(Of MyKey)


    Sub New(ByVal packet As String, ByVal sent As Boolean)
        Me.packet = packet.ToUpper.Trim
        Me.sent = sent
    End Sub

    Public Overloads Function Equals(ByVal other As MyKey) As Boolean Implements IEquatable(Of MyKey).Equals
        Return other.sent = Me.sent AndAlso other.packet = Me.packet
    End Function


    Private packet As String
    Private sent As Boolean
End Class

But to have consistent results I have also to implement Object.Equals and Object.GetHashCode:

Public Class MyKey
    Implements System.IEquatable(Of MyKey)


    Sub New(ByVal packet As String, ByVal sent As Boolean)
        Me.packet = packet.ToUpper.Trim
        Me.sent = sent
    End Sub

    Public Overloads Function Equals(ByVal other As ChiavePietanza) As Boolean Implements IEquatable(Of MyKey).Equals
        Return other.sent = Me.sent AndAlso other.packet = Me.packet
    End Function

    Overrides Function Equals(ByVal o As Object) As Boolean
        Dim cast As MyKey = DirectCast(o, MyKey)
        Return Equals(cast)
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return packet.GetHashCode Or sent.GetHashCode
    End Function


    Private packet As String
    Private sent As Boolean
End Class

The question is: is that GetHashCode implementation correct? How should I implement it, to return a hashcode that kind of merges the string and the boolean hash codes?

like image 750
vulkanino Avatar asked Feb 27 '23 08:02

vulkanino


2 Answers

Your GetHashCode function is correct and conforms to the known rules of hash code implementations. In particular

  • It is the same for value for equivalent instances of MyKey
  • It does not change with changes to MyKey

The one way it could be made better though is to make both packet and sent be ReadOnly fields. Right now it is implied that they are ReadOnly because they are used in a GetHashCode function. However a future developer might overlook that, mutate the values and break the contract needed for GetHashCode. Having them explicitly ReadOnly prevents accidental breaks.

Another minor note. While it's a good idea to implement IEquatable(Of T) for Dictionary keys, it is not a requirement. All that is needed is to override the Equals and GetHashCode method in order to have a key properly function in a Dictionary.

like image 172
JaredPar Avatar answered Mar 07 '23 07:03

JaredPar


Its okayish, but the Or operator doesn't generate well distributed hash values since it can only turn bits on, not off. Use the Xor operator instead.

like image 45
Hans Passant Avatar answered Mar 07 '23 07:03

Hans Passant