52

这就是我想要做的。我正在使用 LINQ to XML 查询一个 XML 文件,它为我提供了一个 IEnumerable <T> 对象,其中 T 是我的“村庄”类,其中填充了此查询的结果。有些结果是重复的,所以我想对 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);
    }
}

由于默认比较器不适用于 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() 看看可能是什么问题。
我在互联网上找到了这样的例子,但我似乎无法让我的实现工作。

希望这里的人可能会看到这里可能出了什么问题!提前致谢!

4

3 回答 3

72

问题出在你的GetHashCode. 您应该更改它以返回哈希码AllianceName

int IEqualityComparer<Village>.GetHashCode(Village obj)
{
    return obj.AllianceName.GetHashCode();
}

问题是,如果Equals返回true,对象应该具有相同的哈希码,而不同Village对象的哈希码相同AllianceName。由于Distinct通过在内部构建哈希表来工作,因此您最终会得到由于不同的哈希码而根本不匹配的相等对象。

同样,比较两个文件,如果两个文件的hash不一样,根本不需要检查文件本身。他们有所不同。否则,您将继续检查它们是否真的相同。这正是Distinct使用的哈希表的行为。

于 2009-01-11T12:32:05.543 回答
11

return alliances.Select(v => v.AllianceName).Distinct();

那将返回一个IEnumerable<string>而不是IEnumerable<Village>

于 2009-12-16T20:16:34.350 回答
7

或者换行

return alliances.Distinct(new AllianceComparer());

return alliances.Select(v => v.AllianceName).Distinct();
于 2009-11-24T04:04:00.540 回答