简体   繁体   English

IEnumerable.Equals似乎调用了错误的Equals方法

[英]IEnumerable.Equals seems to call the wrong Equals method

I implemented a PagedModel class to wrap around IEnumerable to provide paging data for grids in my MVC app. 我实现了一个PagedModel类来包装IEnumerable,为我的MVC应用程序中的网格提供分页数据。 I used Resharper's auto-generated Equality code telling it to check the data, total rows, page number, and page size fields. 我使用了Resharper自动生成的Equality代码,告诉它检查数据,总行数,页码和页面大小字段。 Here's the class code: 这是类代码:

Public Class PagedModel(Of T)
    Public Property PageSize As Integer
    Public Property PageNumber As Integer
    Public Property ModelData As IEnumerable(Of T)
    Public Property TotalRecords As Integer

    Public Overloads Function Equals(ByVal other As PagedModel(Of T)) As Boolean
        If ReferenceEquals(Nothing, other) Then Return False
        If ReferenceEquals(Me, other) Then Return True
        Return other._PageSize = _PageSize AndAlso other._PageNumber = _PageNumber AndAlso Equals(other._ModelData, _ModelData) AndAlso other._TotalRecords = _TotalRecords
    End Function

    Public Overloads Overrides Function Equals(ByVal obj As Object) As Boolean
        If ReferenceEquals(Nothing, obj) Then Return False
        If ReferenceEquals(Me, obj) Then Return True
        If Not Equals(obj.GetType(), GetType(PagedModel(Of T))) Then Return False
        Return Equals(DirectCast(obj, PagedModel(Of T)))
    End Function

    Public Overrides Function GetHashCode() As Integer
        Dim hashCode As Long = _PageSize
        hashCode = CInt((hashCode * 397) Xor _PageNumber Mod Integer.MaxValue)
        If _ModelData IsNot Nothing Then hashCode = CInt(((hashCode * 397) Xor _ModelData.GetHashCode()) Mod Integer.MaxValue)
        hashCode = CInt((hashCode * 397) Xor _TotalRecords Mod Integer.MaxValue)
        Return CInt(hashCode Mod Integer.MaxValue)
    End Function
End Class

I found the call to Equals(other._ModelData, _ModelData) peculiar, as AFAIK, this checks that it is the same object rather than that the contained items are the same. 我发现调用Equals(other._ModelData,_ModelData)是特殊的,因为AFAIK,它检查它是同一个对象而不是包含的项是相同的。 Because my tests were failing anyways, I went ahead and changed it to other._ModelData.Equals(_ModelData) with no success. 因为我的测试无论如何都失败了,我继续将其更改为other._ModelData.Equals(_ModelData)但没有成功。 Then I reflected into it at debug time and found that other._ModelData.GetType().GetMethod("Equals",{GetType(Object)}).DeclaringType was Object! 然后我在调试时反思它,发现other._ModelData.GetType()。GetMethod(“Equals”,{GetType(Object)})。DeclaringType是Object! Obviously, that would result in the failed comparison. 显然,这将导致失败的比较。

I came up with a solution to create a EnumerableEquals method which compares every item in the two enumerables to confirm the are the same, but it seems sloppy. 我想出了一个创建EnumerableEquals方法的解决方案,该方法比较两个枚举中的每个项目以确认它们是相同的,但它看起来很草率。 Is there anything I can do to use the normal .Equals method? 有什么办法可以使用正常的.Equals方法吗?

Private Function EnumerableAreEqual(ByVal a As IEnumerable(Of T), ByVal b As IEnumerable(Of T)) As Boolean
    b = b.ToList() 'avoid multiple query execution
    Return a.All(Function(item) b.Contains(item))
End Function

You probably want to use SequenceEqual . 您可能想要使用SequenceEqual

(new[]{1,2,3}).SequenceEqual(new[]{1,2,3}) // True
(new[]{1,2,3}).SequenceEqual(new[]{3,2,1}) // False
(new[]{1,2,3}).SequenceEqual(new[]{1,2})  // False
(new[]{1,2}).SequenceEqual(new[]{1,2,3})  // False

This will ensure that both IEnumerables have the same elements in the same order. 这将确保两个IEnumerables具有相同顺序的相同元素。

You can't really use the "normal" Equals method, since it's not defined for enumerables (ie, it doesn't do element comparison). 你不能真正使用“普通”Equals方法,因为它没有为枚举定义(即,它不进行元素比较)。 What you have is perfectly fine (*), but if you want to use the Equals syntax, you can consider using the what @StriplingWarrior suggested. 你有什么是完美的(*),但如果你想使用Equals语法,你可以考虑使用@StriplingWarrior建议的内容。

(*) Your implementation doesn't really check whether both are equal. (*)您的实现并不能真正检查两者是否相等。 If 'a' has more elements than 'b', it will return True; 如果'a'的元素多于'b',它将返回True; also, if 'a' has the same elements as 'b', but in a different order, it will also return True. 另外,如果'a'与'b'具有相同的元素,但是以不同的顺序,它也将返回True。 If that's ok for your scenario, then it's fine. 如果你的情况没问题,那就没关系。

In general, for any two arbitrary storage locations X and Y , the value of X.Equals(Y) should never change unless X or Y is written. 通常,对于任意两个任意存储位置XY ,除非写入XY否则X.Equals(Y)的值不应该改变。 While it would be possible for an immutable collection type to override Equals to test sequence equality, mutable class types cannot sensibly do anything with Equals(Object) other than test for reference identity (which is the default behavior). 虽然不可变集合类型可以重写Equals以测试序列相等性,但是可变类类型除了测试引用标识(这是默认行为)之外,不能明智地对Equals(Object)做任何事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM