简体   繁体   English

C#与IEnumerable <T>的区别在于自定义IEqualityComparer

[英]C# Distinct on IEnumerable<T> with custom IEqualityComparer

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. 我正在使用LINQ to XML查询XML文件,它为我提供了一个IEnumerable <T >对象,其中T是我的“Village”类,填充了此查询的结果。 Some results are duplicated, so I would like to perform a Distinct() on the IEnumerable object, like so: 有些结果是重复的,所以我想在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. Distinct()方法不起作用,因为无论是否有相同数量的结果。 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. 另一件事,我不知道它是否通常可行,但我无法进入AllianceComparer.Equals()看看可能是什么问题。
I've found examples of this on the Internet, but I can't seem to make my implementation work. 我在互联网上找到了这方面的例子,但我似乎无法让我的实现工作。

Hopefully, someone here might see what could be wrong here! 希望有人在这里看到可能出错的地方! Thanks in advance! 提前致谢!

The problem is with your GetHashCode . 问题出在你的GetHashCode You should alter it to return the hash code of AllianceName instead. 您应该更改它以返回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 . 问题是,如果Equals返回true ,则对象应该具有相同的哈希码,而对于具有相同AllianceName不同Village对象则不是这种情况。 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. 由于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 will be 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. 这正是Distinct使用的哈希表的行为。

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

这将返回IEnumerable<string>而不是IEnumerable<Village>

Or change the line 或者换行

return alliances.Distinct(new AllianceComparer());

to

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM