在空字段上调用GetHashCode方法?

22

如何在 GetHashCode 函数中处理 null 字段?

Module Module1
  Sub Main()
    Dim c As New Contact
    Dim hash = c.GetHashCode
  End Sub

  Public Class Contact : Implements IEquatable(Of Contact)
    Public Name As String
    Public Address As String

    Public Overloads Function Equals(ByVal other As Contact) As Boolean _
        Implements System.IEquatable(Of Contact).Equals
      Return Name = other.Name AndAlso Address = other.Address
    End Function

    Public Overrides Function Equals(ByVal obj As Object) As Boolean
      If ReferenceEquals(Me, obj) Then Return True

      If TypeOf obj Is Contact Then
        Return Equals(DirectCast(obj, Contact))
      Else
        Return False
      End If
    End Function

    Public Overrides Function GetHashCode() As Integer
      Return Name.GetHashCode Xor Address.GetHashCode
    End Function
  End Class
End Module

异或(XOR)不是结合哈希码的好方法。为了更可靠的方法,请参阅https://dev59.com/EnVC5IYBdhLWcg3wihqv - Jeff Yates
2个回答

38

通常,您需要检查是否为空并在字段为空时为哈希码的这个“部分”使用0:

return (Name == null ? 0 : Name.GetHashCode()) ^ 
  (Address == null ? 0 : Address.GetHashCode());

(抱歉,这是一个C#术语,不确定在VB中的空值检查等效方式)


不用担心“csism”。你刚刚澄清了null的哈希码为0。 - Shimmy Weitzhandler
顺便问一下,如果区分字段是一个整数,我可以返回整数本身而不是它的哈希码吗?那样会不会是个坏主意? 即返回ContactId ^(Name == null?0:Name.GetHashCode)(它是一个整数)? - Shimmy Weitzhandler
2
哈希码的唯一要求是相等的对象返回相等的哈希码。由于相等的整数是相等的,因此将整数作为其自己的哈希码返回是可以的。实际上,这正是Int32.GetHashCode似乎在做的事情...! - itowlson
3
异或(XOR)不是组合哈希码的好方法。为了更可靠的方法,请参见https://dev59.com/EnVC5IYBdhLWcg3wihqv - Jeff Yates
似乎Nullable<T>在HasValue为false时已经返回0了:https://msdn.microsoft.com/zh-cn/library/axk9ks7d(v=vs.110).aspx - Leon van der Walt
@Shimmy 注意,在许多(所有?).NET Framework版本中,存在于System.Int32GetHashCode()方法被覆盖,只返回整数本身。在这种情况下,当ContactId的类型为int时,ContactId.GetHashCode()ContactId相同。当然,您永远不知道实现是否会在将来的.NET版本中更改。 - Jeppe Stig Nielsen

15

正如Jeff Yates所建议的那样,答案中的重写会为(name = null, address = "foo")和(name = "foo", address = null)给出相同的哈希值。这些需要有所区别。如链接所建议的那样,类似下面的代码会更好一些。

public override int GetHashCode()
{
    unchecked // Overflow is fine, just wrap
    {
        int hash = 17;
        hash = hash * 23 + (Name == null ? 0 : Name.GetHashCode());
        hash = hash * 23 + (Address == null ? 0 : Address.GetHashCode());
    }
    return hash;
}

如何为重写的System.Object.GetHashCode()方法选择最佳算法?


5
在C# 7中,(Name == null ? 0 : Name.GetHashCode()) 可以简化为 (Foo?.GetHashCode() ?? 0)。请注意,这个简写不会改变原始代码的含义,只是让它更加简洁易懂。 - Adam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接