【问题标题】:Creating a comparable Dictionary Key创建一个可比较的字典键
【发布时间】:2010-08-30 16:03:13
【问题描述】:

我想用一个 Dictionary(Of Key, Value),而 Key 不是基类型,而是一个类,比如:

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

现在要让 Dictionary 工作并找到键,我必须在 Key 类中实现 System.IEquatable 接口(或使用不同的构造函数,但这是另一回事):

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

但要获得一致的结果,我还必须实现 Object.Equals 和 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

问题是:GetHashCode 实现是否正确?我应该如何实现它,以返回一种将字符串和布尔哈希码合并的哈希码?

【问题讨论】:

标签: c# vb.net collections dictionary


【解决方案1】:

您的 GetHashCode 函数是正确的,并且符合已知的哈希码实现规则。特别是

  • MyKey 的等效实例的值相同
  • 它不会随着MyKey 的更改而改变

一种可以改进的方法是使packetsent 成为ReadOnly 字段。现在暗示它们是ReadOnly,因为它们用于 GetHashCode 函数。然而,未来的开发人员可能会忽略这一点,改变值并打破 GetHashCode 所需的合同。让他们明确地ReadOnly 防止意外中断。

另一个小音符。虽然为Dictionary 键实现IEquatable(Of T) 是个好主意,但这不是必需的。所需要的只是覆盖EqualsGetHashCode 方法,以便使Dictionary 中的密钥正常工作。

【讨论】:

  • 你认为异或这两个字段会更好吗?
  • @vulkanino,可能而且通常是 GetHashCode 的完成方式。但不可能肯定地对这个问题说是或否,因为它过多地取决于packetsent 的实际值。最好的检查方法是用真实数据运行一些测试,看看哪种方法可以更好地分布哈希码值。
【解决方案2】:

它还可以,但是 Or 运算符不会生成分布良好的哈希值,因为它只能打开位,而不是关闭位。请改用 Xor 运算符。

【讨论】:

    【解决方案3】:

    这篇文章是我所有GetHashCode 覆盖的基础:

    SO - What is the best algorithm for an overridden System.Object.GetHashCode? 所以你可以这样做:

    public override int GetHashCode() {
        int hash = 17;
        hash = (hash * 23) + ((packet != null) ? packet.GetHashCode() : 0);
        hash = (hash * 23) + ((sent != null) ? sent.GetHashCode() : 0);
        return hash;
    }
    

    应该直接将其移植到 VB。

    【讨论】:

    • 我实际上是将该类移植到 VB 中,但无法在 VB 中设置“未检查”块 :( 我得到了一个 OverflowException,想法?
    • 我认为高级编译选项下有一个标志允许未经检查的算术。不幸的是,我认为这是一个项目范围的设置,可能不是您想要的。
    • 您总是可以将代码包装在 try-catch 块中,只捕获 OverflowException 并忽略它。
    • @lumberjack4 但是得到的整数是什么??
    • 删除上面的评论。解决此问题的最佳方法是在编译器设置中设置 Remove integer overflow checks 或使用 XOR 哈希方法。
    【解决方案4】:

    如果您想要一些简单的东西,并且性能并不重要,我相信结构类型的字典会将两个结构视为相等,如果它们的所有成员都相等。性能不是很好,但是代码很简单。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多