Подтвердить что ты не робот

С# сравнить два объекта неизвестных типов (включая ссылочные и типы значений)

Можно ли в С# сравнивать два объекта неизвестных типов (включая как ссылочные, так и типы значений) с использованием их компараторов типов, если они существуют?

Цель состоит в том, чтобы написать функцию, которая имела бы такую ​​подпись:

public bool Compare(object a, object b)
{
     // compare logic goes here
}

Что вернет

Compare(100d, 100d) == true
Compare(100f, 100f) == true
Compare("hello", "hello") == true
Compare(null, null) == true 
Compare(100d, 101d) == false
Compare(100f, null) == false

// Use type comparators where possible, i.e.:
Compare(new DateTime(2010, 12, 01), new DateTime(2010, 12, 01)) == true
Compare(new DateTime(2010, 12, 01), new DateTime(2010, 12, 02)) == false
Compare(new DateTime(2010, 12, 01), null) == false

Существует ли общий подход к решению этой проблемы, который будет работать для любого типа объекта?

4b9b3361

Ответ 1

Вы можете использовать статический метод object.Equals(object x, object y) и вообще не писать свой метод. Это будет соответствующим образом обрабатывать нули и делегировать реализацию object.Equals(object), связанную либо с x, либо с y... не имеет значения, что, поскольку Equals означает симметричность.

Обратите внимание, что это не использует операторы == для любого типа. Операторы не могут быть переопределены, только перегружены (что означает, что они выбраны во время компиляции, а не времени выполнения. В большинстве случаев Equals должен делать то, что вам нужно. В некоторых случаях == не может быть перегружен, даже если Equals переопределен... но я никогда не знал, чтобы обратное было истинным в любых типах, с которыми я работал.

Обратите внимание, что при использовании этого подхода будут введены все типы значений...

EDIT: удалена секция об эффективном переопределении - плохо - EqualityComparer<T>.Default. См. Ответ Марка для получения дополнительной информации. Это не поможет вам, если вы не можете использовать общий тип, конечно.

Один последний момент: я бы не назвал ваш метод Compare. Это имя обычно ассоциируется с порядковыми значениями, а не с их сравнением для равенства.

Ответ 2

Разумным вариантом является работа с дженериками, т.е.

public bool Compare<T>(T a, T b) {...}

Вам не нужно указывать T в вашем коде, поскольку компилятор обычно сможет его вычислить (т.е. ваши существующие образцы будут работать как "есть" )

Для реализации:

bool equal = EqualityComparer<T>.Default.Equals(x, y);

(для общего типа T)

но на самом деле я бы избегал слова Compare, так как он используется в другом месте для обозначения </==/> - поэтому я мог бы:

public static bool Equals<T>(T a, T b) {
    return EqualityComparer<T>.Default.Equals(a, b);
}

Это:

  • избегает бокса, когда T является структурой
  • корректно обрабатывает nulls/Nullable<T>
  • поддерживает IEquatable<T>
  • или возвращается к регулярному Equals

он использует не оператор ==, но у MiscUtil есть класс Operator, который через

bool equal = Operator.Equal<T>(x,y);

(обратите внимание, что последнее не будет выполнено, если T не имеет оператора ==, хотя, думая об этом, он мог бы использовать EqualityComparer<T>.Default.Equals как резерв, просто это не делает)


Для полноты заметим, что Comparer<T>.Default.Compare(x,y) обрабатывает операции сравнения.

Ответ 3

Как насчет object.equals(x, y)? Это также примет нулевые значения.

Ответ 4

Что насчет

if (a == null && b == null) return true;
if (a == null && b != null) return false;
return (a.equals(b));

?

Ответ 5

Я не уверен на 100%, если это работает во всех случаях, но попробуйте

public bool Compare(object a, object b)
{
    return a.Equals(b);
}