Реализовали ли IEquatable правильно? Должен ли я всегда переопределять GetHashCode? - PullRequest
2 голосов
/ 18 марта 2012

Я видел вопрос, заданный здесь: Правильно ли я реализовал Equals () / GetHashCode ()? но мой c # не так силен, и я не настолько похож на IEquatable, что хотел бы увидеть это пожалуйста, в VB.NET.

Мой пример кода (в конце концов класс будет использовать INotifyPropertyChanged):

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

Спасибо

Ответы [ 2 ]

3 голосов
/ 18 марта 2012

Вам действительно нужно реализовать переопределения для реализаций object.Equals и object.GetHashCode.

По сути, реализация IEquatable (из T) .Equals сама по себе будет работать только до тех пор, пока вызывающая программа УЗНАЕТ вызывать IEquatable (из T) .Equals вместо обычного object.Equals.

Подумайте, есть ли у вас ArrayList of Cars, и проверьте, содержит ли список (myCar), где Марка и Модель myCar такие же, как и у автомобиля в ArrayList ... но тот, который в ArrayList, на самом деле не является точным тот же экземпляр. Содержит вернул бы ложь.

Еще хуже, если у вас есть Hashtable или Dictionary, который использует GetHashCode для определения места хранения записей, равенство никогда не сработает, потому что две машины с одинаковыми марками и моделями будут возвращать разные значения для GetHashCode ()

По сути, все сводится к тому, что вы добавляете в машину следующие реализации:

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

Итак, у меня вопрос: зачем вообще реализовывать IEquatable? Почему бы просто не переопределить Equals и GetHashCode?

1 голос
/ 20 марта 2012

Реализуйте IEquatable<T> только для структур или закрытых классов. Любая законная реализация IEquatable<T>.Equals(T) должна иметь семантику, совместимую с переопределением класса Object.GetHashCode(), которое, в свою очередь, должно иметь семантику, совместимую с переопределением класса Equals(Object). Если тип не запечатан, единственный способ гарантировать, что реализация производных типов IEquatable<T>.Equals(T) будет совместима с их переопределением Object.Equals(Object), состоит в том, чтобы иметь цепочку первого метода ко второму, фактически сводя на нет любое преимущество, которое может иметь полученный от реализации IEquatable<T> в первую очередь.

Реализация IEquatable<T> часто является большим выигрышем для структурных типов (экономит упаковочную операцию при каждом сравнении) и несколько меньшим выигрышем для других запечатанных типов (сохраняет типовое преобразование при каждом сравнении). Если производительность не критична, я бы, вероятно, пропустил ее для большинства неструктурных типов, даже если они запечатаны.

...