C# 在 IEnumerable<T> 上与自定义 IEqualityComparer 不同
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/432829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# Distinct on IEnumerable<T> with custom IEqualityComparer
提问by Fueled
Here's what I'm trying to do. I'm querying an XML file using LINQ to XML, which gives me an IEnumerable<T
> object, where T is my "Village" class, filled with the results of this query. Some results are duplicated, so I would like to perform a Distinct() on the IEnumerable object, like so:
这就是我想要做的。我正在使用 LINQ to XML 查询 XML 文件,它为我提供了一个 IEnumerable <T
> 对象,其中 T 是我的“Village”类,其中填充了此查询的结果。有些结果是重复的,所以我想对 IEnumerable 对象执行 Distinct(),如下所示:
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);
}
}
As the default comparer would not work for the Village object, I implemented a custom one, as seen here in the AllianceComparer class:
由于默认比较器不适用于 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
}
The Distinct() method doesn't work, as I have exactly the same number of results with or without it. Another thing, and I don't know if it's usually possible, but I cannot step into AllianceComparer.Equals() to see what could be the problem.
I've found examples of this on the Internet, but I can't seem to make my implementation work.
Distinct() 方法不起作用,因为无论有没有它,我的结果数量都完全相同。另一件事,我不知道这通常是否可行,但我无法进入 AllianceComparer.Equals() 以查看可能是什么问题。
我在互联网上找到了这样的例子,但我似乎无法使我的实现工作。
Hopefully, someone here might see what could be wrong here! Thanks in advance!
希望这里的人可能会看到这里有什么问题!提前致谢!
采纳答案by Mehrdad Afshari
The problem is with your GetHashCode
. You should alter it to return the hash code of AllianceName
instead.
问题出在你的GetHashCode
. 您应该更改它以返回 的哈希码AllianceName
。
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.AllianceName.GetHashCode();
}
The thing is, if Equals
returns true
, the objects should have the same hash code which is not the case for different Village
objects with same AllianceName
. Since Distinct
works by building a hash table internally, you'll end up with equal objects that won't be matched at all due to different hash codes.
问题是,如果Equals
返回true
,对象应该具有相同的哈希码,对于Village
具有相同AllianceName
. 由于Distinct
通过在内部构建哈希表来工作,因此由于不同的哈希码,您最终将得到完全不匹配的相等对象。
Similarly, to compare two files, if the hash of two files are not the same, you don't need to check the files themselves at all. They willbe different. Otherwise, you'll continue to check to see if they are really the same or not. That's exactly what the hash table that Distinct
uses behaves.
同理,比较两个文件,如果两个文件的hash不一样,根本不需要检查文件本身。他们会有所不同。否则,您将继续检查它们是否真的相同。这正是Distinct
使用的哈希表的行为。
回答by Jacob Seleznev
Or change the line
或者换线
return alliances.Distinct(new AllianceComparer());
to
到
return alliances.Select(v => v.AllianceName).Distinct();
回答by superrcat
return alliances.Select(v => v.AllianceName).Distinct();
return alliances.Select(v => v.AllianceName).Distinct();
That would return an IEnumerable<string>
instead of IEnumerable<Village>
.
那将返回一个IEnumerable<string>
而不是IEnumerable<Village>
。