С# Отличие от IEnumerable <T> с пользовательским IEqualityComparer
Вот что я пытаюсь сделать. Я запрашиваю XML файл с использованием LINQ to XML, который дает мне объект IEnumerable <T
> , где T - мой класс "Деревня", заполненный результатами этого запроса. Некоторые результаты дублируются, поэтому я хотел бы выполнить Distinct() для объекта IEnumerable, например:
public IEnumerable<Village> GetAllAlliances()
{
try
{
IEnumerable<Village> alliances =
from alliance in xmlDoc.Elements("Village")
where alliance.Element("AllianceName").Value != String.Empty
orderby alliance.Element("AllianceName").Value
select new Village
{
AllianceName = alliance.Element("AllianceName").Value
};
// TODO: make it work...
return alliances.Distinct(new AllianceComparer());
}
catch (Exception ex)
{
throw new Exception("GetAllAlliances", ex);
}
}
Поскольку сопоставитель по умолчанию не будет работать для объекта Village, я внедрил пользовательский, как показано здесь в классе AllianceComparer:
public class AllianceComparer : IEqualityComparer<Village>
{
#region IEqualityComparer<Village> Members
bool IEqualityComparer<Village>.Equals(Village x, Village y)
{
// Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y))
return true;
// Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.AllianceName == y.AllianceName;
}
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.GetHashCode();
}
#endregion
}
Метод Distinct() не работает, так как у меня точно такое же количество результатов с ним или без него. Другое дело, и я не знаю, возможно ли это, но я не могу войти в AllianceComparer.Equals(), чтобы узнать, что может быть проблемой.
Я нашел примеры этого в Интернете, но я не могу заставить свою работу выполнить.
Надеюсь, кто-то здесь может увидеть, что здесь может быть неправильно!
Спасибо заранее!
Ответы
Ответ 1
Проблема с вашим GetHashCode
. Вы должны изменить его, чтобы вместо хэш-кода AllianceName
.
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.AllianceName.GetHashCode();
}
Дело в том, что если Equals
возвращает true
, объекты должны иметь одинаковый хеш-код, который не подходит для разных объектов Village
с тем же AllianceName
. Поскольку Distinct
работает, создавая хэш-таблицу внутри, вы получите равные объекты, которые не будут согласованы вообще из-за разных хеш-кодов.
Аналогично, чтобы сравнить два файла, если хэш двух файлов не одинаковый, вам не нужно вообще проверять файлы. Они будут быть разными. В противном случае вы будете продолжать проверять, действительно ли они одинаковы или нет. Именно то, что ведет хэш-таблица, используемая Distinct
, ведет себя.
Ответ 2
return alliances.Select(v => v.AllianceName).Distinct();
Это вернет IEnumerable<string>
вместо IEnumerable<Village>
.
Ответ 3
Или измените строку
return alliances.Distinct(new AllianceComparer());
к
return alliances.Select(v => v.AllianceName).Distinct();