Have implemented IEquatable correctly? Should I always override GetHashCode?

StackOverflow https://stackoverflow.com/questions/9756539

  •  24-05-2021
  •  | 
  •  

سؤال

I saw the question posed here: Have I implemented Equals()/GetHashCode() correctly? but my c# is not as strong, and I am unfimiliar with IEquatable enough that I would like to see this in VB.NET if possible please.

My example code (The class will eventually use INotifyPropertyChanged when I get there):

Public Class Car
Implements ICloneable
Implements IEquatable(Of Car)

Public Property Make() As String
    Get
        Return m_Make
    End Get
    Set(ByVal value As String)
        m_Make = value
    End Set
End Property
Private m_Make As String

Public Property Model() As String
    Get
        Return m_Model
    End Get
    Set(ByVal value As String)
        m_Model = value
    End Set
End Property
Private m_Model As String

Public Function Clone() As Object Implements System.ICloneable.Clone
    Return New Car() With { _
     .Make = Me.Make, _
     .Model = Me.Model _
    }
End Function

Public Overloads Function Equals(ByVal other As Car) As Boolean Implements System.IEquatable(Of Car).Equals
    Return other.Make = Me.Make AndAlso other.Model = Me.Model
End Function 
End Class

Thanks,

هل كانت مفيدة؟

المحلول

You really do need to implement Overrides for the object.Equals and object.GetHashCode implementations.

Basically, implementing IEquatable(of T).Equals by itself will only work so long as the caller KNOWS to call IEquatable(of T).Equals instead of regular object.Equals.

Consider if you have an ArrayList of Cars and check if the list Contains(myCar), where myCar's Make and Model are the same as a car in the ArrayList...but the one in the ArrayList isn't actually the exact same instance. Contains would return false.

Worse yet, if you had a Hashtable or Dictionary, which uses GetHashCode to determine where to store entries, equality would never work because two cars with the same Make and Model would return different values for GetHashCode()

Basically, it comes down to you adding the following implementations to car:

Public Overrides Overloads Function Equals(obj As Object) As Boolean
    Return TypeOf obj Is Car AndAlso Equals(DirectCast(obj, Car)) 
End Function 

Public Overrides Function GetHashCode() As Int32
    Dim hash As Int32 = 179 ' or something intelligent

    hash = hash * 27 + Make.GetHashCode()
    hash = hash * 27 + Model.GetHashCode()

    Return hash
End Function

So the question I have is: why implement IEquatable at all? Why not just override Equals and GetHashCode?

نصائح أخرى

Only implement IEquatable<T> for structs or sealed classes. Any legitimate implementation of IEquatable<T>.Equals(T) needs to have semantics compatible with the class's override of Object.GetHashCode(), which must in turn have semantics compatible with the class's override of Equals(Object). If a type is not sealed, the only way to ensure that derived types' implementation of IEquatable<T>.Equals(T) will be compatible with their override of Object.Equals(Object) will be to have the former method chain to the latter, effectively nullifying any advantage one might have obtained from implementing IEquatable<T> in the first place.

Implementing IEquatable<T> is often a big win for struct types (saves a boxing operation on every comparison), and a somewhat smaller win for other sealed types (saves a typecast on every comparison). Unless performance is critical, I'd probably skip it for most non-struct types, even if they're sealed.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top