![]() |
|
Модераторы: diadiavova, gambit |
![]()
|
|
| diadiavova |
|
||||||||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 8 Всего: 142 |
В ряде случаев возникает необходимость реализации интерфейса IEqualityComparer(Of T). Это может понадобиться для работы инструкции Distinct в LINQ-запросах или соответствующей функции, для удаления из коллекции повторяющихся элементов, в ситуации, когда равенство объектов надо определить по-своему; и для коллекции
System.Collections.Generic.HashSet(Of T), которая не принимает двух одинаковых объектов, однако их "одинаковость" может определяться при помощи объекта реализующего данный интерфейс. В целом реализация этого интерфейча не вызывала бы сложностей, если бы не одно "но", а именно - функция GetHashCode. Начнём по порядку. System.Collections.Generic.IEqualityComparer(Of T) Имеет два метода: Equality - принимает два аргумента сравниваемого типа и возвращает булево значение(True - если объекты следует считать равными, и False - в ином случае). Именно в этом методе реализуется вся логика сравнения. GetHashCode - принимает объект сравниваемого типа и возвращает соответствующее ему число типа Integer. Со вторым методом как раз и порой и возникают проблемы. В общем-то ограничений на то, каким должно быть это число нет, но есть одно правило: если метод Equals для двух объектов возвращает True, то метод GetHashCode должен для них обоих возвращать одно и то же число, в противном случае числа должны быть разными. О том, как реализовать этот метод здесь и пойдёт речь. На самом деле идея достаточно проста: Создаём параметризированный абстрактный(MustInherits) класс, в котором метод GetHashCode уже будет реализован и привязан к методу Equals(не реализованному). Для учёта сравнивавшихся ранее объектов создадим в классе поле типа Dictionary, а для того, чтобы иметь неповторяющиеся хэш-коды счётчик(поле типа Integer). Оба поля должны быть статическими, поскольку должны учитывать все объекты сравниваемого типа, независимо от того, какой экземпляр нашего компоратора использовался ранее для сравнения объектов. Сразу хочу оговориться, что то, что мы сейчас создадим не будет как следует работать во всех случаях. Это всего лишь направление, в котором можно "копать", и готовый код для использования в самых простейших случаях. Вот собственно код компаратора.
Как этим пользоваться? Для тестирования создадим простой класс с двумя полями и конструктором, инициирующим эти поля.
Далее наследуем созданный нами компоратор, так, чтобы он сравнивал экземпляры нашего класса MyItemType
На что здесь следует обратить внимание, так это на то, что мы реализуем в нашем классе-наследнике только метод Equals, независимо от того, какую логику мы в него заложим. Далее для проверки функциональности создадим такую функцию
Вызвав эту функцию мы получим результат 3. Потому, что метод Distinct(кстати, для того, чтобы он был доступен в код надо импортировать пространство имён System.Linq)с нашим компоратором посчитает последние три объекта уже присутствующими в коллекции и не возвратит их. Если в последних трёх элементах поменять значение строк
то все шесть элементов останутся в коллекции, что в общем-то нормально(ведь объекты не равны). Но если признаком равенства мы будем считать равенство только по полю IntField, а значение поля StrField в расчёт принимать не будем. То есть наш компоратор будет выглядеть так
То наша функция снова будет возвращать 3. Не смотря на то, что строковые поля не равны, при сравнении они учитываться не будут. То есть всё работает. Есть правда у этого приёма и недостатки. Например, если объект, для которого уже ранее вызывался метод GetHashCode изменится и станет "равным" другому объекту, который уже тоже содержится в коллекции, то коды они выдадут разные, и тут возможно множество вариантов, ну да я с самого начала указал, что всех проблем этот пример не решит. Это сообщение отредактировал(а) diadiavova - 25.10.2009, 00:30 -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит |
||||||||||||
|
|||||||||||||
![]()
|
| Правила форума VB .NET | |
|
|
Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, diadiavova. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | VB .NET | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |