Удивительное равенство Tuple (in)
До сегодняшнего дня мое понимание классов .NET Tuple
состояло в том, что они делегировали их реализацию Equals()
в их содержимое, позволяя мне приравнивать и сравнивать их "по значению".
Затем этот тест пришел и сделал из меня дурака:
[TestMethod]
public void EquateTwoTuplesWithSameContent()
{
var t1 = Tuple.Create("S");
var t2 = Tuple.Create((object)t1.Item1);
Assert.IsTrue(t1.Equals(t2)); // Boom!
}
Чтение через документацию MSDN и различные блоги оставили мне больше вопросов. Из того, что я собираю, казалось бы, что Tuple<object>
и Tuple<TWhatever>
всегда считаются не равными, независимо от того, что оба экземпляра могут обернуть один и тот же объект (в коробке или typecast - все равно).
Действительно ли это как Tuples
должно вести себя? Является ли структурная совместимость фактически дополнительным ограничением на равенство, а не релаксацией, поскольку я до сих пор его интерпретировал?
Если это так, есть ли что-нибудь еще в BCL, которое я могу использовать для удовлетворения ожиданий вышеупомянутого unit test?
Заранее благодарю вас!
Ответы
Ответ 1
Корреспонденты требуют, чтобы для объектов, считающихся "равными", было истинно следующее:
- Должен быть объект Tuple с тем же числом общих параметров (ов), что и текущий объект.
- Каждый из этих общих параметров должен быть того же типа, что и другой.
- Каждый член кортежа должен иметь то же значение, что и соответствующий член другого.
Итак, поскольку a Tuple<object>
имеет другой общий параметр, чем a Tuple<string>
, они не равны, даже если объект фактически является ссылкой на строку с тем же значением, что и строго типизированный Tuple<string>
.
Ответ 2
Да, я бы сказал, что как кортежи должны вести себя. Здесь у вас два разных типа кортежей - Tuple<string>
и Tuple<object>
.
Документация для Tuple<T1>.Equals
утверждает, что два условия:
- Это объект
Tuple<T1>
. - Его единственный компонент имеет тот же тип, что и текущий экземпляр.
Это неверно, если вы спросите, равен ли Tuple<string>
Tuple<object>
, поэтому он возвращает false.
В целом я считаю, что очень плохая идея для экземпляров двух разных типов, которые считаются равными друг другу. Он предлагает всевозможные проблемы.
Ответ 3
На самом деле, как предполагается, что кортежи ведут себя? Является ли структурная совместимость фактически дополнительным ограничением на равенство, а не релаксацией, поскольку я до сих пор его интерпретировал?
Tuple<T1>
реализует IStructuralEquatable
- который, по его имени, делает именно это - проверяет структуру, а также содержимое.
Вы всегда можете переработать свой Unit test, чтобы проверить содержимое элемента кортежа на равенство, а не на сам Tuple.