如何为字典键使用自定义类型?
How do you use a custom type for a dictionary key?
我有一个使用泛型的自定义 class。
我需要使用这个 class 作为字典的键,如下面的代码示例所示:
我可以使用覆盖的 Object.GetHashCode
方法,但我不确定如何从那里继续。请帮忙,谢谢。
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
和 Equals
:
' 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
'
' 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' 从未添加到词典中,并且 'c' 与 a
是不同的对象。但是使用的覆盖只是根据 相同的 2 个值测试对象。
我不认为我会这样做,因为 a<>c
。相反,可以使用某种集合 class 并避免重新定义 Equals
。确切的实现将取决于集合中的内容。对我来说,这是最后的手段。
另请参阅:
- IEquatable
- Why is it important to override GetHashCode when Equals method is overridden?
- Dictionary Reference Source
我有一个使用泛型的自定义 class。
我需要使用这个 class 作为字典的键,如下面的代码示例所示:
我可以使用覆盖的 Object.GetHashCode
方法,但我不确定如何从那里继续。请帮忙,谢谢。
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
和 Equals
:
' 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
'
' 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' 从未添加到词典中,并且 'c' 与 a
是不同的对象。但是使用的覆盖只是根据 相同的 2 个值测试对象。
我不认为我会这样做,因为 a<>c
。相反,可以使用某种集合 class 并避免重新定义 Equals
。确切的实现将取决于集合中的内容。对我来说,这是最后的手段。
另请参阅:
- IEquatable
- Why is it important to override GetHashCode when Equals method is overridden?
- Dictionary Reference Source