首页 > 解决方案 > C# Hashset.Contains 与自定义 EqualityComparer 从不调用 GetHashCode()

问题描述

我的数据库中有一个非常大(数十万)的客户对象哈希集。然后我得到一个新导入的客户对象哈希集,并且必须检查每个新对象,如果它包含在现有哈希集中。性能非常重要。

我不能使用默认的 Equalitycomparer,因为它只需要基于三个属性进行比较。此外,由于其他原因,我无法覆盖 Customer 类的 Equals 和 GetHashCode 函数。因此,我的目标是自定义 EqualityComparer(我尝试实现 IEqualityComparer 或从 EqualityComparer 继承并像您在下面看到的那样覆盖 - 两者都具有相同的最终结果)。

public class CustomerComparer : EqualityComparer<Customer>
    {
        public CustomerComparer(){ }

        public override bool Equals(Customer x, Customer y)
        {
            return x != null &&
                   y != null &&
                   x.Name == y.Name &&
                   x.Description == y.Description &&
                   x.AdditionalInfo == y.AdditionalInfo
        }

        public override int GetHashCode(Customer obj)
        {
            var hashCode = -1885141022;
            hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(obj.Name);
            hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(obj.Description);
            hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(obj.AdditionalInfo);
            return hashCode;
        }
    }

现在我的问题是:当我使用默认的 EqualityComparer 时,通常只调用 Customer 的 GetHashCode 方法,并且我的用例的性能非常好(1-2 秒)。当我使用我的自定义 EqualityComparer 时,永远不会调用 GetHashCode 方法,但总是调用 Equals 方法。我的用例的性能很糟糕(几个小时)。请参见下面的代码:

public void FilterImportedCustomers(ISet<Customer> dataBase, IEnumerable<Customer> imported){

    var equalityComparer = new CustomerComparer();
    foreach (var obj in imported){
        
        //great performance, always calls Customer.GetHashCode
        if (!dataBase.Contains(obj){
        //...
        }

        //awful performance, only calls CustomerComparer.AreEqual
        if (!dataBase.Contains(obj, equalityComparer))
        //...
        }            
    }
}

有谁知道,我该如何解决这个问题?那将是惊人的,我真的被困在试图解决这个巨大的性能问题。

编辑 :

我在初始化哈希集时通过传递我的 EuqalityComparer 解决了这个问题!通过使用采用 IEqualityComparer 的构造函数重载,因此 var database = new HashSet(new CustomerComparer())

感谢你们!

标签: c#performancelinqcontainshashset

解决方案


我通过在初始化哈希集时传递我的 EqualityComparer 来解决它!使用采用 IEqualityComparer 的构造函数重载,因此 var database = new HashSet(new CustomerComparer())

感谢 Lee 和 NetMage 在我原来的帖子下发表评论。


推荐阅读