Як сказано в назві: чи потрібно перевизначати ==
оператора? як щодо .Equals()
методу? Щось мені не вистачає?
Як сказано в назві: чи потрібно перевизначати ==
оператора? як щодо .Equals()
методу? Щось мені не вистачає?
Відповіді:
Приклад із msdn
public struct Complex
{
double re, im;
public override bool Equals(Object obj)
{
return obj is Complex c && this == c;
}
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
public static bool operator ==(Complex x, Complex y)
{
return x.re == y.re && x.im == y.im;
}
public static bool operator !=(Complex x, Complex y)
{
return !(x == y);
}
}
Complex other = obj as Complex
а потім перевірити, чи не other == null
замість використання, is
а потім акторський склад
Complex? other = obj as Complex?
, але типи, що допускають обнулення , часто не піддаються ефективності.
MyComplex
як ви пропонуєте.
Вам також слід реалізувати IEquatable <T>. Ось уривок із керівних принципів проектування:
ВБЕРІТИ IEquatable на типи значень. Метод Object.Equals для типів значень спричиняє бокс, і його реалізація за замовчуванням не дуже ефективна, оскільки використовує посилання. IEquatable.Equals може запропонувати набагато кращу продуктивність і може бути реалізований так, щоб це не спричиняло боксу.
public struct Int32 : IEquatable<Int32> {
public bool Equals(Int32 other){ ... }
}
ВИКОРИСТОВУЙТЕ ті самі вказівки, що й для перевизначення Object.Equals при впровадженні IEquatable.Equals. Див. Розділ 8.7.1 для детальних вказівок щодо заміни Object.Equals
На жаль, у мене недостатньо репутації, щоб коментувати інші записи. Тож я публікую тут можливе вдосконалення найкращого рішення.
Виправте мене, якщо я помиляюся, але реалізація згадана вище
public struct Complex
{
double re, im;
public override bool Equals(Object obj)
{
return obj is Complex && this == (Complex)obj;
}
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
public static bool operator ==(Complex x, Complex y)
{
return x.re == y.re && x.im == y.im;
}
public static bool operator !=(Complex x, Complex y)
{
return !(x == y);
}
}
Має великий недолік. Я посилаюся на
public override int GetHashCode()
{
return re.GetHashCode() ^ im.GetHashCode();
}
XORing є симетричним, тому Complex (2,1) і Complex (1,2) дадуть однаковий хеш-код.
Напевно, нам слід зробити щось подібне:
public override int GetHashCode()
{
return re.GetHashCode() * 17 ^ im.GetHashCode();
}
Здебільшого ви можете уникати реалізації Equals і GetHashcode у структурах, оскільки компілятор автоматично реалізує типи типів, використовуючи побітове вміст + відображення для посилальних членів.
Погляньте на цю публікацію: Що найкраще підходить для структури / класів сховища даних?
Отже, для зручності використання ви все ще можете застосувати == та! =.
Але більшу частину часу ви можете уникати впровадження рівних та GetHashcode.
Випадок, коли вам довелося б застосувати Equals і GetHashCode, - це поле, яке ви не хочете брати до уваги.
Наприклад, поле, яке змінюється з часом, наприклад Вік людини або миттєва швидкість автомобіля (ідентичність об’єкта не повинна змінюватися, якщо ви хочете знайти його там же в словнику)
З повагою, найкращий код
Основна різниця між ними полягає в тому, що ==
оператор є статичним, тобто відповідний метод, який потрібно викликати, визначається під час компіляції, тоді як Equals
метод викликається динамічно на екземплярі.
Визначення обох - це, мабуть, найкраще, навіть якщо це менш важливо у випадку структур, оскільки структури не можуть бути розширені (структура не може успадкувати від іншої).
Для повноти я б порадив також Equals
метод перевантаження :
public bool Equals(Complex other)
{
return other.re == re && other.im == im;
}
це справжнє вдосконалення роздумів, оскільки не відбувається боксу вхідного аргументу Equals(Object obj)
методу
Деякі найкращі практики використання типів цінностей:
Це випливає з цієї публікації: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/