Ответ 1
EDIT: вот код для вашего обновленного примера. Примечание. Мне показалось немного странным, что вы открываете поле как защищенное, а также имеете виртуальное свойство, которое предоставляет член. Под этой схемой что-то может переопределить Length
, что приведет к равенству, которое смотрит на _lenght
, чтобы не вести себя так, как ожидалось.
public class Duration : IEquatable<Duration>
{
protected double _length;
/// <summary>
/// Gets or Sets the duration in Miliseconds.
/// </summary>
public virtual double Length
{
get { return _length; }
set { _length = value; }
}
// removed all the other code that as it was irrelevant
public bool Equals(Duration other)
{
// First two lines are just optimizations
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return _length.Equals(other._length);
}
public override bool Equals(object obj)
{
// Again just optimization
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
// Actually check the type, should not throw exception from Equals override
if (obj.GetType() != this.GetType()) return false;
// Call the implementation from IEquatable
return Equals((Duration) obj);
}
public override int GetHashCode()
{
// Constant because equals tests mutable member.
// This will give poor hash performance, but will prevent bugs.
return 0;
}
}
См. EqualityComparer.Default для информации о стандартном IEqualityComparer
, используемом классом Dictionary.
Если вы не хотите вообще переопределять GetHashCode
и Equals
в классе, или если вы не можете. Существует перегрузка конструктора Dictionary , в которой вы можете указать конкретный IEqualityComparer
для использования.
Это простой интерфейс для реализации, но вам нужно быть осторожным, чтобы вы соблюдали контракт для GetHashCode
, или вы можете оказаться в неожиданном поведении.
public class MyObjectEqualityComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.TypeID == y.TypeID;
}
public int GetHashCode(MyObject obj)
{
return obj.TypeID; //Already an int
}
}
использовать его просто go
new Dictionary<MyObject, int>(new MyObjectEqualityComparer());
Если вы хотите использовать IEqualityComparer по умолчанию, вам необходимо предоставить примерно одинаковые методы в MyObjectEqualityComparer. Вы можете избегать переопределения object.Equals()
, если вы реализуете IEquatable. Однако я бы сильно отговорил его, потому что это может привести к неожиданному поведению. Вам лучше переопределить Equals
, чтобы у вас было последовательное поведение для всех вызовов Equals и иметь хеширование, которое правильно соответствует Equals. Мне пришлось исправить ошибку в унаследованном коде, вызванную прошлым разработчиком, реализующим только IEquatable.