当可变字段是相等的一部分时,如何实现IEquatable <t> - GetHashCode的问题</t>

时间:2010-04-13 03:45:55

标签: equals hashset mutable gethashcode iequatable

我在我的应用程序中使用Entity Framework。

我使用IEquatable<T>接口的实体的部分类实现:

Partial Class Address : Implements IEquatable(Of Address) 'Other part generated
  Public Overloads Function Equals(ByVal other As Address) As Boolean _
      Implements System.IEquatable(Of Address).Equals
    If ReferenceEquals(Me, other) Then Return True
    Return AddressId = other.AddressId
  End Function

  Public Overrides Function Equals(ByVal obj As Object) As Boolean
    If obj Is Nothing Then Return MyBase.Equals(obj)
    If TypeOf obj Is Address Then 
      Return Equals(DirectCast(obj, Address)) 
  Else
    Return False
  End Function

  Public Overrides Function GetHashCode() As Integer
    Return AddressId.GetHashCode
  End Function
End Class

现在在我的代码中我用这种方式:

Sub Main()
  Using e As New CompleteKitchenEntities
    Dim job = e.Job.FirstOrDefault
    Dim address As New Address()

    job.Addresses.Add(address)
    Dim contains1 = job.Addresses.Contains(address) 'True
    e.SaveChanges()
    Dim contains2 = job.Addresses.Contains(address) 'False

    'The problem is that I can't remove it:
    Dim removed = job.Addresses.Remoeve(address) 'False

  End Using
End Sub

注意(我在调试器可视化器中检查过)EntityCollection类将其实体存储在HashSet中,因此它与GetHashCode函数有关,我希望它依赖于ID,因此实体将通过它们的ID进行比较。

问题是当我点击保存时,ID会从0更改为其db值。 所以问题是我如何才能拥有一个等分的对象,并进行适当的散列。

请帮我查一下GetHashCode函数中的错误(通过ID)以及我可以更改什么来使其正常工作。

非常感谢。

2 个答案:

答案 0 :(得分:1)

你已经使用了一个可变字段(AddressId)作为哈希的一部分 - 遗憾的是注定了这一点。我的意思是:当你添加它时,AddressId是0? -1? 完全是什么并不重要,但它不是最终的id - 它与这个key / hash一起存储。保存时,实际 id(数据库中的IDENTITY列)将更新到对象中。

很简单,不能可靠地对此值进行哈希处理,如果它在字典的一部分时可以更改。一种可能的解决方法是考虑工作单元,即插入是一个工作单元。含义:如果数据等仅与此一样存在,那么这是一个非问题,因为您在保存数据后永远不会尝试访问数据。随后(在不同的上下文中)加载数据也应该没问题,因为id在生命周期内不会改变。

或者:删除此哈希/相等。

答案 1 :(得分:1)

非密封类不应实现IEquatable<T>,因为确保覆盖Object.Equals()Object.GetHashCode()的派生类将以一致的方式实现IEquatable<BaseType>的唯一方法Object.GetHashCode()的{​​{1}}用于调用虚拟Object.Equals(Object)方法的接口实现。由于IEquatable<T>的唯一目的是避免调用Object.Equals(Object)的开销,并且在未密封的类上安全地实现IEquatable<T>无法避免调用它,因此这样的实现没有任何意义。

此外,我强烈反对任何可变类类型的Object.Equals(或IEquatable<T>的实现)的覆盖。结构,无论是否可变,都可以覆盖Object.EqualsObject.GetHashCode,并实现IEquatable<theirOwnType>,因为结构的字段存储为例如{1}}。即使struct类型公开了可变的公共字段,Dictionary键也是不可变的。