Что на самом деле делает System.Collections.Generic.Dictionary <T, T> .Equals? - PullRequest
2 голосов
/ 23 декабря 2008

Я столкнулся с этим сегодня, когда проводил модульное тестирование универсального словаря.

System.Collections.Generic.Dictionary<int, string> actual, expected;
actual = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
expected = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
Assert.AreEqual(expected, actual); //returns false
Сбой

, за исключением случаев, когда actual == expected (ссылки на объекты совпадают). Очевидно, actual.Equals(expected) также возвращает false.

Хорошо, но если реализация System.Collections.Generic.Dictionary<int, string>.Equals только ссылается на равенство, какой смысл IEquatable? Другими словами, почему не существует встроенного способа сделать равенство значений для родовых коллекций?

Редактировать Спасибо за ответы до сих пор. Очевидно, мой пример использует типы значений, но я думаю, что моя жалоба относится ко всем объектам. Почему родовое равенство коллекций не может быть просто объединением равенств его типов? Неожиданное поведение на самом деле не сокращает его, поскольку существуют отдельные положения для нахождения ссылочного равенства. Я предполагаю, что это введет ограничение коллекций, содержащих только объект, который реализует IEquatable, как указывает Конрад Рудольф. Тем не менее, в таком объекте, как словарь, это не так много, чтобы спросить.

Ответы [ 3 ]

2 голосов
/ 23 декабря 2008

Другими словами, почему не существует встроенного способа сделать равенство значений для родовых коллекций?

Возможно, потому что это трудно сформулировать в общих терминах, поскольку это было бы возможно только в том случае, если бы тип значения (и тип ключа) словаря также реализовал IEquatable. Однако требование этого будет слишком сильным, что сделает Dictionary непригодным для использования со многими типами, которые не реализуют этот интерфейс.

Это врожденная проблема с ограниченными дженериками. Haskell предлагает решение этой проблемы, но для этого требуется гораздо более мощный и сложный механизм генериков.

Обратите внимание, что нечто подобное верно для IComparable по сравнению с контейнерами, но есть поддержка для этого, при необходимости используется Comparer<T>.Default.

2 голосов
/ 23 декабря 2008

Dictionary<T,T>.Equals наследуется от Object.Equals и, таким образом, выполняет простое сравнение ссылок на объекты.

Почему родовые коллекции не имеют смысловой семантики равенства? Потому что это может быть не то, что вы хотите. Иногда вы хотите проверить, являются ли они одним и тем же экземпляром. Что бы сделала альтернатива? Вызывать равно на каждый из ключей и значений? Что если они наследуют Equals от Object? Это не будет полное глубокое сравнение.

Так что вы должны предоставить какую-то другую семантику, если и когда это необходимо.

1 голос
/ 23 декабря 2008

Dictionary<TKey, TValue> не реализует IEquatable, так как не существует формального способа определить / узнать, что на самом деле даст сравнение одного такого словаря с другим с тем же содержанием.

Фактически, Dictionary<TKey, TValue> вообще не реализует ни один из интерфейсов сравнения.

По моему мнению, сравнивать два объекта - это довольно особенная вещь, поэтому было бы гораздо разумнее поместить это в интерфейс, чем просто поместить стандартную нежелательную реализацию по умолчанию в базовый класс Object. Это должна была быть более рекламируемая особенность класса, чем то, что может сделать каждый объект, хотя и не совсем так, как вы ожидаете.

Но у вас это есть. Он там, и вам нужно знать, когда он будет использоваться.

Как в этом случае.

...