2014-09-19 1 views
2

У меня есть сценарий, когда метод расширения IEnumerable.SequenceEqual возвращает false, когда я этого не ожидал - если быть точным, при использовании его для сравнения двух наборов (известных идентичных) ILookup<int, int>. Через отладчик я обнаружил, что фактические элементы в моих двух коллекциях являются экземплярами класса Lookup<TKey, TElement>.Grouping, поэтому я погрузился в исходный источник.Почему Lookup <TKey, TValue>. Класс группировки не обеспечивает переопределения равенства?

Чтобы сократить длинный рассказ, сравнительный коэффициент равенства по умолчанию, используемый SequenceEqual, равен ObjectEqualityComparer, по умолчанию используется стандарт Object.Equals. Но Lookup<TKey, TElement>.Grouping не отменяет Equals, поэтому ObjectEqualityComparer заканчивает с использованием методы по умолчанию Object.Equals, который вызывает в RuntimeHelpers.Equals, которые (я предполагаю, так как это extern) делает ссылочное сравнение и возвращают ложь.

Я не вижу веской причины, почему полужирная часть должна быть правдой, следовательно, этот вопрос. Кто-нибудь знает (или может объяснить), если это было преднамеренное дизайнерское решение (и если да, почему) - или это просто непреднамеренное упущение?

ответ

2

Публично Lookup<TKey, TElement>.Grouping всего лишь IEnumerable<TElement>.

В целом, два экземпляра IEnumerable<TElement>: не равномерно, потому что их элементы равны.

Почему эта конкретная реализация IEnumerable<TElement> будет отличаться?

+0

«... два экземпляра IEnumerable не равны только потому, что их элементы равны. Почему эта конкретная реализация IEnumerable будет отличаться?» Когда вы вкладываете его в эти термины, это имеет смысл. –

1

Никакая коллекция в BCL не переопределяет членов равенства. Это конвенции они придерживаются.

Почему? Спекуляция: Профиль производительности может быть неожиданным. Или, по их мнению, сравнение ссылок было бы более полезным. Или они обнаружили, что повсеместно невозможно определить правильное равенство (например, MatchCollection). Таким образом, они решили, по крайней мере, согласных.

Я не вижу причин, почему IGrouping был бы особенно полезным кандидатом для применения методов равенства. Практически так же полезно иметь это, как и в любой другой коллекции.

Напишите себе CollectionEqualityComparer<T> и используйте его везде.

0

Если класс является изменяемым, каким-либо конкретным переменной или временным хранением этого типа может инкапсулировать любого из нескольких вещей:

  1. Единственного упоминание в любой точке вселенной к экземпляру этого класса.

  2. Ссылка на экземпляр этого класса, который запрещается изменять всем.

  3. Ссылка на экземпляр этого класса, к которому могут существовать другие ссылки, но который принадлежит владельцу переменной или месту хранения и не будет изменен без ведома владельца.

  4. Ссылка на экземпляр этого класса, который принадлежит кому-либо другому, и может быть изменен без ведома владельца переменной или места хранения.

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

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

Смежные вопросы