C# отличается от IEnumerable<T> с помощью специального IEqualityComparer
-
10-07-2019 - |
Вопрос
Вот что я пытаюсь сделать.Я запрашиваю 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(), чтобы посмотреть, в чем может быть проблема.
Я нашел примеры этого в Интернете, но, похоже, моя реализация не работает.
Надеюсь, кто-нибудь здесь увидит, что здесь может быть не так!Заранее спасибо!
Решение
Проблема в вашем GetHashCode
. Вы должны изменить его так, чтобы вместо него возвращался хеш-код AllianceName
.
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.AllianceName.GetHashCode();
}
Дело в том, что если Equals
возвращает true
, объекты должны иметь один и тот же хэш-код, что не относится к разным объектам Village
с тем же AllianceName
. Поскольку Distinct
работает путем внутреннего построения хеш-таблицы, вы получите одинаковые объекты, которые не будут сопоставляться вообще из-за разных хеш-кодов. Р>
Аналогично, для сравнения двух файлов, если хэш двух файлов не совпадает, вам вообще не нужно проверять сами файлы. Они будут разными. В противном случае вы продолжите проверять, действительно ли они одинаковы или нет. Это именно то, что ведет себя хеш-таблица, которую использует Distinct
.
Другие советы
вернуть alliances.Select (v = > v.AllianceName) .Distinct ();
Это вернуло бы IEnumerable < string >
вместо IEnumerable < Village >
.
Или измените строку
return alliances.Distinct(new AllianceComparer());
к
return alliances.Select(v => v.AllianceName).Distinct();