Загальні значення рівності (тотожність) в C #

Який найкращий (найбільш стислий та оптимальний) спосіб порівняння двох екземплярів того ж загального типу, що типи посилання для ідентичності порівнюють (той самий об'єкт, так що не викликаючи Equals ) та значення для значення рівність .

В даний час я роблю це:

static bool IdentityEquals(T x, T y)
{
    return typeof(T).IsValueType
        ? EqualityComparer.Default.Equals(x, y)
        : ReferenceEquals(x, y);
}
5
Чи може C# перевантажувати загальним витонченням?
додано Автор user2246674, джерело
Чи може C# перевантажувати загальним витонченням?
додано Автор user2246674, джерело

6 Відповіді

Ви повинні мати можливість просто використовувати object.Equals для типів значень:

 return typeof(T).IsValueType
    ? object.Equals(x, y)
    : ReferenceEquals(x, y);
5
додано
@ MarcinWisnicki ти просиш "найкраще (найкоротший")
додано Автор Blorgbeard, джерело
Це повільніше завдяки боксу.
додано Автор Marcin Wisnicki, джерело
На жаль, я оновив вимогу включити також "оптимальний" ;-P Я дійсно сподівався на який-небудь метод, який використовує порівняння ідентичності, наприклад, ReferenceEquals (), але не порушує тип типів.
додано Автор Marcin Wisnicki, джерело
@zespri Насправді вбудовані типи значень (int, string тощо) всі реалізують IEquatable , що, ймовірно, уникає боксів при використанні EqualityComparer .
додано Автор D Stanley, джерело
@ MarcinWisnicki лаконічний та виконавський цілком може бути конкуруючими цілями. Вам може знадобитися вибрати, який з них є більш важливим.
додано Автор D Stanley, джерело
@Дстантлі: так, ви маєте рацію. Моє ліжко.
додано Автор Andrew Savinykh, джерело
@ MarcinWisnicki, обидва способи пов'язані з боксом.
додано Автор Andrew Savinykh, джерело

Ви повинні мати можливість просто використовувати object.Equals для типів значень:

 return typeof(T).IsValueType
    ? object.Equals(x, y)
    : ReferenceEquals(x, y);
5
додано
@ MarcinWisnicki ти просиш "найкраще (найкоротший")
додано Автор Blorgbeard, джерело
Це повільніше завдяки боксу.
додано Автор Marcin Wisnicki, джерело
На жаль, я оновив вимогу включити також "оптимальний" ;-P Я дійсно сподівався на який-небудь метод, який використовує порівняння ідентичності, наприклад, ReferenceEquals (), але не порушує тип типів.
додано Автор Marcin Wisnicki, джерело
@ MarcinWisnicki лаконічний та виконавський цілком може бути конкуруючими цілями. Вам може знадобитися вибрати, який з них є більш важливим.
додано Автор D Stanley, джерело
@zespri Насправді вбудовані типи значень (int, string тощо) всі реалізують IEquatable , що, ймовірно, уникає боксів при використанні EqualityComparer .
додано Автор D Stanley, джерело
@ MarcinWisnicki, обидва способи пов'язані з боксом.
додано Автор Andrew Savinykh, джерело
@Дстантлі: так, ви маєте рацію. Моє ліжко.
додано Автор Andrew Savinykh, джерело

На жаль, .NET лише визначає один стандартний метод віртуального Equals та один метод GetHashCode , хоча існують два логічні питання, які можуть запитати це питання (питання є найпростішими, якщо припускати що X і Y - змінні того ж типу):

  1. Could one replace `X` with a reference to `Y`, or vice versa, without affecting the present or future behavior of any members thereof?
  2. If one were to simultaneously make all references to the target of `X` point to `Y`, and all references to the target of `Y` point to `X`, would all members of `X` and `Y` continue to behave the same?

Припустимо, X і Y тримають посилання на два об'єкти типу int [1] , які зараз містять значення 42. Деякі зовнішні коди мають посилання на той самий екземпляр, що й Y , і збирається збільшити його. Якщо потрібно змінити X , щоб вказати ті самі випадки, що й Y , це змінить майбутнє значення X [0] .

З іншого боку, припустімо, що у двох об'єктів кожне з них має приватне поле, кожен з яких містить єдине посилання, яке існує в будь-якій точці Всесвіту, до свого власного int [1] , що тримають і завжди тримають значення 42, і не викликало RuntimeHelpers.GetHashCode() , що викликається у цьому екземплярі. Незважаючи на те, що int [1] є змінним типом, два вищезазначені екземпляри повинні вважатися еквівалентними, оскільки міняють "всі посилання" [тобто. єдиний довідник] до першого з усіма посиланнями на другу не матиме впливу на поведінку програми. Якщо один масив тримав 23, а другий - 27, однак обмін посиланнями міняв би, який об'єкт мав посилання на 23 і який мав 27.

Зверніть увагу: якщо додавати твердження "об'єкти різних типів не можуть бути еквівалентними, оскільки їхні методи GetType() обов'язково будуть поводитися по-різному", то обидва питання вище можуть бути отримані відповідним чином і однозначно для об'єктів будь-якого класу тип, а другий можна відповісти значущим чином для будь-якого типу значення. Відповіді стануть значущими визначеннями як еквівалентності, так і рівності цінностей. Звичайна поведінка .NET Equals перевизначає, як правило, відповідають типи відповідей на перше запитання (коду є більш імовірний інтерес до нього), і типи значень відповідають другому (оскільки перший буде безглуздо для них) . Оскільки це звучить так, що поведінка за замовчуванням - це те, що ви хочете, можливо, ви могли б описати, чи є ситуація, коли це не так?

[примітка: кілька типів .NET типу Decimal визначають Equals у вільному порядку; два вищезазначених питання були б добрими, на які відповідали універсальні віртуальні методи].

0
додано

На жаль, .NET лише визначає один стандартний метод віртуального Equals та один метод GetHashCode , хоча існують два логічні питання, які можуть запитати це питання (питання є найпростішими, якщо припускати що X і Y - змінні того ж типу):

  1. Could one replace `X` with a reference to `Y`, or vice versa, without affecting the present or future behavior of any members thereof?
  2. If one were to simultaneously make all references to the target of `X` point to `Y`, and all references to the target of `Y` point to `X`, would all members of `X` and `Y` continue to behave the same?

Припустимо, X і Y тримають посилання на два об'єкти типу int [1] , які зараз містять значення 42. Деякі зовнішні коди мають посилання на той самий екземпляр, що й Y , і збирається збільшити його. Якщо потрібно змінити X , щоб вказати ті самі випадки, що й Y , це змінить майбутнє значення X [0] .

З іншого боку, припустімо, що у двох об'єктів кожне з них має приватне поле, кожен з яких містить єдине посилання, яке існує в будь-якій точці Всесвіту, до свого власного int [1] , що тримають і завжди тримають значення 42, і не викликало RuntimeHelpers.GetHashCode() , що викликається у цьому екземплярі. Незважаючи на те, що int [1] є змінним типом, два вищезазначені екземпляри повинні вважатися еквівалентними, оскільки міняють "всі посилання" [тобто. єдиний довідник] до першого з усіма посиланнями на другу не матиме впливу на поведінку програми. Якщо один масив тримав 23, а другий - 27, однак обмін посиланнями міняв би, який об'єкт мав посилання на 23 і який мав 27.

Зверніть увагу: якщо додавати твердження "об'єкти різних типів не можуть бути еквівалентними, оскільки їхні методи GetType() обов'язково будуть поводитися по-різному", то обидва питання вище можуть бути отримані відповідним чином і однозначно для об'єктів будь-якого класу тип, а другий можна відповісти значущим чином для будь-якого типу значення. Відповіді стануть значущими визначеннями як еквівалентності, так і рівності цінностей. Звичайна поведінка .NET Equals перевизначає, як правило, відповідають типи відповідей на перше запитання (коду є більш імовірний інтерес до нього), і типи значень відповідають другому (оскільки перший буде безглуздо для них) . Оскільки це звучить так, що поведінка за замовчуванням - це те, що ви хочете, можливо, ви могли б описати, чи є ситуація, коли це не так?

[примітка: кілька типів .NET типу Decimal визначають Equals у вільному порядку; два вищезазначених питання були б добрими, на які відповідали універсальні віртуальні методи].

0
додано

Either implement IEquatable on your types of interest, along with overrides of object.Equals() and object.GetHashCode(), or provide an instance of IEqualityComparer to your type consumer.

DOT NET doesn't implement your definition of equality because then it wouldn't be mine, or Fred's down the street. Instead it provides the tools for you to build exactly what you need, without stepping on my toes or ibiting what I need to build..

0
додано
Насправді, поняття ідентичності є добре визначена і абсолютно важлива для реалізації популярних візерунків дизайну (наприклад, "Observer" - ви повинні відрізняти об'єкт об'єкта відстежувати правильні об'єкти).
додано Автор Marcin Wisnicki, джерело
Так, .NET Framework має дуже заплутану історію, коли мова йде про об'єкт рівності та ідентичності. Тож цілком ймовірно, що визначення Фреда буде іншим. Див. Главу 5 "CLR через C #" Дж. Ріхтера, щоб спосіб, як це могло бути зроблено (за допомогою MS), було б менш заплутаним.
додано Автор Andrew Savinykh, джерело

Either implement IEquatable on your types of interest, along with overrides of object.Equals() and object.GetHashCode(), or provide an instance of IEqualityComparer to your type consumer.

DOT NET doesn't implement your definition of equality because then it wouldn't be mine, or Fred's down the street. Instead it provides the tools for you to build exactly what you need, without stepping on my toes or ibiting what I need to build..

0
додано
Насправді, поняття ідентичності є добре визначена і абсолютно важлива для реалізації популярних візерунків дизайну (наприклад, "Observer" - ви повинні відрізняти об'єкт об'єкта відстежувати правильні об'єкти).
додано Автор Marcin Wisnicki, джерело
Так, .NET Framework має дуже заплутану історію, коли мова йде про об'єкт рівності та ідентичності. Тож цілком ймовірно, що визначення Фреда буде іншим. Див. Главу 5 "CLR через C #" Дж. Ріхтера, щоб спосіб, як це могло бути зроблено (за допомогою MS), було б менш заплутаним.
додано Автор Andrew Savinykh, джерело
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug