Кортеж == Путаница

Предположим, что я определяю два набора:

Tuple<float, float, float, float> tuple1 = new Tuple<float, float, float, float>(1.0f, 2.0f, 3.0f, 4.0f);
Tuple<float, float, float, float> tuple2 = new Tuple<float, float, float, float>(1.0f, 2.0f, 3.0f, 4.0f);

Если я попытаюсь сравнить кортежи, я получаю разные результаты

bool result1 = (tuple1 == tuple2);    // FALSE
bool result2 = tuple1.Equals(tuple2); // TRUE

Я ожидал бы, что оба вызова возвратят true. Что именно сравнивается ==?

Ответы

Ответ 1

Для Tuple, == сравнивает ссылки на объекты, потому что он не перегружает оператор ==. Поскольку объекты эквивалентны, но не один и тот же конкретный экземпляр, Equals() возвращает true и == возвращает false.

Многие типы не перегружают ==, некоторые предпочитают проводить различие между Equals() для эквивалентности и == для ссылочного равенства.

Кроме того, полагаясь на == для эквивалентности, может привести к некоторой странности:

public bool AreSame<T>(T first, T second) where T : class
{
    return first == second;
}

Приведенный выше код всегда будет проверять ссылочное равенство, потому что неограниченное общее значение считается во время компиляции object, поэтому, если метод не является виртуальным, вы получите версию объекта (даже если тип, например string перегрузки ==).

Таким образом, это использование вышеуказанного кода:

var x = "Hello";
var y = "H";

// doing concat to avoid string interring
AreSame(x, y+"ello");

Да, строки эквивалентны, да T есть string, но == привязан к объекту ==, поскольку общий не имеет ограничений, поэтому он вернет false, хотя тот же код с явные параметры string возвращают true.

Ответ 2

== сравнивает ссылки на объекты. Класс Tuple не перегружает оператор ==, поэтому вам нужно использовать .Equals.

Ответ 3

== для Tuple будут видеть только ссылки и, следовательно, вы увидите, что это ложь.

PS: Рекомендуемый способ - сделать что-то вроде:

var tuple1 = Tuple.Create(1.0f, 2.0f, 3.0f, 4.0f)