如何使用自定义类型的字典键? [英] How do you use a custom type for a dictionary key?

查看:179
本文介绍了如何使用自定义类型的字典键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用泛型的自定义类。

I have a custom class which uses generics.

我需要使用这个类作为字典的键,如下面的代码示例所示:

I need to use this class as the key of a dictionary as shown in the code example below:

我可以击中覆盖的 Object.GetHashCode 方法,但我不知道如何从那里继续。请帮忙,谢谢。

I am able to hit the overridden Object.GetHashCode method, but i'm not sure how to proceed from there. Please help, Thanks.

    Module Module2
    Dim myStore As New Dictionary(Of Pair(Of Long, Integer), String)

    Public Function ContainsItem(id As Long, code As Integer) As Boolean
        Return myStore.ContainsKey(New Pair(Of Long, Integer)(id, code))
    End Function

    Public Class Pair(Of T1, T2)
        Implements IEquatable(Of Pair(Of T1, T2))

        Private v1 As T1
        Private v2 As T2

        Public Sub New(ByVal v1 As T1, ByVal v2 As T2)
            Me.v1 = v1
            Me.v2 = v2
        End Sub

        Public Function first() As T1
            Return v1
        End Function

        Public Function second() As T2
            Return v2
        End Function

        Public Overrides Function GetHashCode() As Integer
            'i hit this break point, but ... 
            'how do i compute an integer hashcode from a long and an Integer?
            Return MyBase.GetHashCode()
        End Function

        Public Overrides Function Equals(obj As Object) As Boolean
            Return MyBase.Equals(obj)
        End Function

        Public Function Equals1(other As Pair(Of T1, T2)) As Boolean Implements IEquatable(Of Pair(Of T1, T2)).Equals
            'just as a test, but the code never gets here.
            Return True
        End Function
    End Class

    Public Sub TestCase()
        Dim a = New Pair(Of Long, Integer)(10, 10)
        myStore.Add(a, "Item 1")

        Dim b = ContainsItem(10, 10)
        'b is always false 
    End Sub
End Module


推荐答案

这将实现 IEquatable 并覆盖 GetHashCode 等于

' an assumption about Pair(Of... :
Public Class Pair(Of T, TT)
    Implements IEquatable(Of Pair(Of T, TT))

    Public Property ValueT As T
    Public Property ValueTT As TT

然后,方法:

' basic Equals for this Type
Public Overrides Function Equals(obj As Object) As Boolean
    If obj.GetType Is GetType(Pair(Of Long, Integer)) Then
        Return Equals1(CType(obj, Pair(Of T, TT)))
    Else
        Return False
    End If
End Function

' used by the Dictionary 
Public Function Equals1(obj As Pair(Of T, 
                 TT)) As Boolean Implements IEquatable(Of Pair(Of T, TT)).Equals
    ' the other thing is Something Else
    If obj.GetType <> GetType(Pair(Of Long, Integer)) Then
        Return False
    End If

    'prefer T over TT, testing first
    If Integer.Equals(obj.ValueT, ValueT) = False Then
        Return False
    End If

    'T is equal, what about TT:
    Return Long.Equals(obj.ValueTT, ValueTT)
End Function

 ' dictionary will use the hashcode for ContainsKey, Add
Public Overrides Function GetHashCode() As Integer
    ' https://stackoverflow.com/a/371348/1070452
    ' marc gravell:
    Dim hash As Integer = 13
    hash = (hash * 7) + ValueT.GetHashCode()
    hash = (hash * 7) + ValueTT.GetHashCode()

    Return hash

    ''msdn (non generic value types):
    'Dim hCode As Long = ValueT Xor ValueTT
    'Return hCode.GetHashCode()
End Function

测试:

Dim a = New Pair(Of Long, Integer)(10, 10)
Dim b = New Pair(Of Long, Integer)(5, 5)
' different object, same values:
Dim c = New Pair(Of Long, Integer)(10, 10)

Dim mydict As New Dictionary(Of Pair(Of Long, Int32), String)
mydict.Add(a, "ziggy")
mydict.Add(b, "zoey")

Console.WriteLine("a==b? {0}", a.Equals(b).ToString)
Console.WriteLine("a==c? {0}", a.Equals(c).ToString)
Console.WriteLine("b==c? {0}", b.Equals(c).ToString)

Console.WriteLine("Contains a? {0}", mydict.ContainsKey(a).ToString)
Console.WriteLine("Contains b? {0}", mydict.ContainsKey(b).ToString)
' since the c OBJECT is not in the collection, it SHOULD report false
 ' but since the values are, and thats all that seems to matter:
Console.WriteLine("Contains c? {0}", mydict.ContainsKey(c).ToString)

结果:

a==b? False
a==c? True
b==c? False
Contains a? True
Contains b? True
Contains c? True

使用 c 的测试实际上是错误的,对象'c'添加到Dictionary中,'c'是与 a 不同的对象,但是使用的覆盖只是根据 的2个值来测试对象>相同。

The tests using c are actually false. The object 'c' was never added to the Dictionary, and 'c' is a different object than a. But the overrides used simply tests the objects based on the 2 values which are the same.

我不认为我会这样做,因为 a<> c 。相反,也许使用某种类的集合类,并避免重新定义等于。确切的实现将取决于集合中的内容。

I do not think I would do this, because a<>c. Instead, maybe use a collection class of some sort and avoid redefining Equals. The exact implementation would depend on whats in the collection. This would be a last resort, for me.

另请参见:

  • IEquatable
  • Why is it important to override GetHashCode when Equals method is overridden?
  • Dictionary Reference Source

这篇关于如何使用自定义类型的字典键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆