Freigeben über


Equality isn't easy

After my recent postings on the rules of Equality, I thought it would be a good idea to post a simple example of equality.  The class in question, Example, has only one field of type Integer name m_field1.  Two instances of Example are equal if m_field1 has the same value.  So the real equality check is just a single Integer comparison. 

Unfortunately, as my posts alluded to, even though the check is simple getting it right is not necessarily so.  The equality portion of example takes roughly 20 lines of code while the actual equality check represents only 1 of those lines [1].  Not a good ratio.  The good and bad news about the other 19 lines is they are boiler plate so once you know them you don't have to think about them.  For my own purposes I've converted those 19 lines into a snippet which automates the process but doesn't make it any easier on the eye.

 Class Example
    Implements IEquatable(Of Example)

    Private ReadOnly m_field1 As Integer
    Public Sub New(ByVal field As Integer)
        m_field1 = field
    End Sub

    Public Function Equals1(ByVal other As Example) As Boolean Implements System.IEquatable(Of Example).Equals
        If other Is Nothing Then
            Return False
        End If

        Return m_field1 = other.m_field1
    End Function

    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Return Equals1(TryCast(obj, Example))
    End Function

    Public Overrides Function GetHashCode() As Integer
        Return m_field1.GetHashCode
    End Function

    Public Shared Operator =(ByVal left As Example, ByVal right As Example) As Boolean
        Return EqualityComparer(Of Example).Default.Equals(left, right)
    End Operator

    Public Shared Operator <>(ByVal left As Example, ByVal right As Example) As Boolean
        Return Not EqualityComparer(Of Example).Default.Equals(left, right)
    End Operator

End Class

Module Module1

    Sub AssertTrue(ByVal cond As Boolean)
        Debug.Assert(cond, "failure")
    End Sub

    Sub AssertFalse(ByVal cond As Boolean)
        Debug.Assert(Not cond, "failure")
    End Sub

    Sub Main()
        Dim v1 As New Example(1)
        Dim v2 As New Example(2)
        Dim v3 As New Example(1)

        AssertFalse(v1 Is v2)
        AssertFalse(v1 Is v3)
        AssertTrue(v1 Is v1)
        AssertFalse(v1 = v2)
        AssertTrue(v1 = v3)
        AssertFalse(v1 = Nothing)
        AssertFalse(Nothing = v1)
        AssertTrue(v1 <> v2)
        AssertTrue(v1 <> Nothing)
        AssertTrue(EqualityComparer(Of Example).Default.Equals(v1, v3))
        AssertFalse(EqualityComparer(Of Example).Default.Equals(v1, v2))
    End Sub

End Module

[1] Before VB criticism enters, C# has roughly the same ratio for the same sample. 

Comments