Вы правы, это много стандартного кода, и вам нужно реализовать все по отдельности.
Я бы порекомендовал:
- Если вы собираетесь реализовать равенство значений вообще, переопределите
GetHashCode
и Equals(object)
- создание перегрузок для == и реализация IEquatable<T>
без этого может привести к очень неожиданному поведению
- Я бы всегда реализовывал
IEquatable<T>
, если вы переопределяете Equals(object)
и GetHashCode
- Я реже перегружаю оператор ==
- Правильно реализовать равенство для открытых классов сложно, и все же может привести к неожиданным / нежелательным результатам. Если вам нужно равенство для типов в иерархии, реализуйте
IEqualityComparer<T>
, выражая интересующее вас сравнение.
- Равенство для изменяемых типов обычно является плохой идеей, поскольку два объекта могут быть равны, а затем неравны после этого ... если объект видоизменяется (влияющим на равенство) после того, как он используется в качестве ключа в хэш-таблице вы не сможете найти его снова.
- Некоторые элементы котла немного отличаются для структур ... но, как и Марк, я очень редко пишу свои собственные структуры.
Вот пример реализации:
using System;
public sealed class Foo : IEquatable<Foo>
{
private readonly string name;
public string Name { get { return name; } }
private readonly int value;
public int Value { get { return value; } }
public Foo(string name, int value)
{
this.name = name;
this.value = value;
}
public override bool Equals(object other)
{
return Equals(other as Foo);
}
public override int GetHashCode()
{
int hash = 17;
hash = hash * 31 + (name == null ? 0 : name.GetHashCode());
hash = hash * 31 + value;
return hash;
}
public bool Equals(Foo other)
{
if ((object) other == null)
{
return false;
}
return name == other.name && value == other.value;
}
public static bool operator ==(Foo left, Foo right)
{
return object.Equals(left, right);
}
public static bool operator !=(Foo left, Foo right)
{
return !(left == right);
}
}
И да, это чертовски много шаблонного, очень мало чего меняется между реализациями: (
Реализация ==
на немного менее эффективна, чем могла бы быть, так как она вызовет Equals(object)
, который должен выполнить динамическую проверку типа ... но альтернатива еще более варочная панель, вот так:
public static bool operator ==(Foo left, Foo right)
{
if ((object) left == (object) right)
{
return true;
}
// "right" being null is covered in left.Equals(right)
if ((object) left == null)
{
return false;
}
return left.Equals(right);
}