C# C在IEnumerable上使用自定义IEqualityComparer进行区分
这就是我要做的。我正在使用LINQtoXML查询一个XML文件,它给了我一个IEnumerable对象,其中T是我的Village类,填充了这个查询的结果。有些结果是重复的,因此我想对IEnumerable对象执行一个Distinct,如下所示:C# C在IEnumerable上使用自定义IEqualityComparer进行区分,c#,linq-to-xml,ienumerable,distinct,C#,Linq To Xml,Ienumerable,Distinct,这就是我要做的。我正在使用LINQtoXML查询一个XML文件,它给了我一个IEnumerable对象,其中T是我的Village类,填充了这个查询的结果。有些结果是重复的,因此我想对IEnumerable对象执行一个Distinct,如下所示: public IEnumerable<Village> GetAllAlliances() { try { IEnumerable<Village> alliances =
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。看看会有什么问题。
我在互联网上找到了这样的例子,但我似乎无法使我的实现工作
希望这里有人能看到这里可能出了什么问题!
提前谢谢 问题在于GetHashCode。您应该改为返回AllianceName的哈希代码
问题是,如果Equals返回true,那么对象应该具有相同的哈希代码,而对于具有相同AllianceName的不同村庄对象,情况并非如此。由于Distinct是通过在内部构建哈希表来工作的,因此最终会得到由于哈希代码不同而根本不匹配的相等对象
类似地,要比较两个文件,如果两个文件的哈希不相同,则根本不需要检查文件本身。他们会有所不同。否则,您将继续检查它们是否真的相同。这正是Distinct使用的哈希表的行为。或更改行
return alliances.Distinct(new AllianceComparer());
到
返回联盟。选择v=>v.AllianceName.Distinct
这将返回IEnumerable而不是IEnumerable。您的catch/throw构造使调用函数无法再选择catchArgumentException或catchIOException示例。在这种情况下,您最好一起删除try/catch-此外,该方法的名称将是exception StackTrace属性的一部分。为什么我们不能只覆盖Distinct???@Boog的典型相等方法?当然,您可以在对象本身或单独的相等比较器类中执行此操作,如OP所愿。自定义相等比较器的使用情况是当您有不同的方法来考虑对象相等或不相等时,例如对字符串敏感或不区分大小写的比较,或者由于任何原因无法更改类本身。在任何情况下,您都应该重写Equals和GetHashCode,并针对Equals方法编写一个适当的GetHashCode。这是一种有趣的替代方法,它会导致提问者重新思考使用IEqualityComparer的代码。这为我解决了一个问题,这就是为什么我喜欢它。不过,这并没有回答这个问题。在我的例子中,我想从键值数据集合中提取唯一键,并将唯一键单独存储在列表中。正如@supercat所提到的,通过这样做,返回的IEnumerable的泛型类型会发生变化。
return alliances.Distinct(new AllianceComparer());
return alliances.Select(v => v.AllianceName).Distinct();