Search code examples
asp.netvb.netasp.net-4.0iequalitycomparer

Custom Equals function not being called when using IEqualityComparer


I have created a IEqualityComparer for my classes that represent objects from a database and I wanted to override the Equals method of these classes so it'd compare the Id of the object when calling Equals, Contains etc. The problem is that my Equals function is never called, can anyone see why the test would always return false?

Thanks!

DatabaseEntityEqualityComparer.vb

Imports System.Collections.Generic

Public Class DatabaseEntityEqualityComparer
    Implements IEqualityComparer(Of IDatabaseEntity)

    Public Overloads Function Equals(x As IDatabaseEntity, y As IDatabaseEntity) As Boolean Implements IEqualityComparer(Of IDatabaseEntity).Equals

        'check whether the compared objects reference the same data
        If x Is y Then Return True

        'check whether any of the compared objects is null
        If x Is Nothing OrElse y Is Nothing Then Return False

        'check whether the IDatabaseEntity properties are equal, and are of the same type
        Return (x.Id = y.Id) AndAlso (x.GetType() = y.GetType())

    End Function

    Public Overloads Function GetHashCode(obj As IDatabaseEntity) As Integer Implements IEqualityComparer(Of IDatabaseEntity).GetHashCode

        If obj Is Nothing Then
            Return 0
        End If

        Return obj.Id.ToString().GetHashCode()

    End Function

End Class

IDatabaseEntity.vb

Public Interface IDatabaseEntity

    Property Id As Integer

End Interface

Person.vb

Public Class Person
    Implements IDatabaseEntity

    Public Property Id As Integer Implements IDatabaseEntity.Id

End Class

Run the test

Dim p1 As New Person()
p1.Id = 1

Dim p2 As New Person()
p2.Id = 1

If p1.Equals(p2) Then
    Response.Write("Equals")            
Else
    Response.Write("Not Equals")
End If

Response.End()

Solution

  • An IEqualityComparer is an interface that allows to create a custom euqality comparer. You can use it for example in many LINQ methods like Intersect,Except,GroupBy,Join etc. But you have to pass an instance of the comparer to these methods.

    If you want to change override Equals and GetHashCode in general:

    Public Class Person
        Implements IDatabaseEntity
    
        Public Property Id As Integer Implements IDatabaseEntity.Id
    
        Public Overrides Function Equals(obj As Object) As Boolean
            If obj Is Nothing Then Return False
            If Object.ReferenceEquals(Me, obj) Then Return True
            Dim Person2 As Person = TryCast(obj, Person)
            If Person2 Is Nothing Then Return False
            Return Person2.Id = Id
        End Function
    
        Public Overrides Function GetHashCode() As Integer
            Return Id
        End Function
    
    End Class
    

    If you want to use your comparer, you can use it's Equals in this way:

    Dim comparer = New DatabaseEntityEqualityComparer()
    If comparer.Equals(p1, p2) Then
        Response.Write("Equals")   
    End If