为什么我不能在 IEqualityComparer<Customer> Equals 方法中使用 customer.Name.contains("smith")

Why can I not use customer.Name.contains("smith") in IEqualityComparer<Customer> Equals method

我想使用 HashSet.Contains 方法,因为它超级快。

var hashset = new HashSet<Customer>(customers, new CustomerComparer());
var found = hashset.Contains(new Customer{ Id = "1234", Name = "mit" }); // "mit" instead of an equals "smith" in the comparer.

我正在搜索客户对象的多个属性。

我必须像这样实现 IEqualityComparer 接口:

public class CustomerComparer : IEqualityComparer<Customer>
{
    public bool Equals(Customer x, Customer y)
    {
        return x.Id == y.Id && x.Name.Contains(y.Name);
    }      

    public int GetHashCode(Customer obj)
    {
        return obj.Id.GetHashCode() ^ obj.Name.GetHashCode();
    }
}

当我不使用 CustomerComparer Equals 方法(如 .Contains)中的 Equals 方法时,为什么 Equals 方法永远不会命中?

您实现相等比较器的方式无法正常工作。原因是散列集和相等比较器在内部是如何工作的。当 DictionaryHashSet 对项目进行比较时,它将首先对两个项目调用 GetHashCode。只有当这些哈希码匹配时,它才会通过随后调用 Equals 来确认完全匹配,以避免在哈希码冲突的情况下出现错误匹配。如果您使用您的示例(x.Name = "smith"y.Name = "mit"),GetHashCode 方法将为每个项目 return 不同的哈希码并且永远不会调用 Equals

这种情况下的解决方案是仅使用 Id 来创建哈希码。这会稍微降低性能,因为您必须更频繁地调用 Equals 来解决冲突,但这是您必须付出的代价:

public int GetHashCode(Customer obj)
{
    return obj.Id.GetHashCode() ;
}

您还应该考虑的是,您无法保证您现有的项目是 x 还是 y。所以你必须在两个方向上使用Contains

public bool Equals(Customer x, Customer y)
{
    return x.Id == y.Id && (x.Name.Contains(y.Name) || y.Name.Contains(x.Name));
}      

Why is the Equals method never hit when I do NOT use an Equals method inside the CustomerComparer Equals method like the .Contains?

仅当您的 "customers" 集合中存在至少一项与您传递给 HashSet 的 Contains 方法的 Customer 对象具有相同的散列码时,才会命中 Equals 方法。如果您 运行 以下示例程序,您将看到 Equals 方法确实被命中:

public static class Program
{
    public class Customer
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

    public class CustomerComparer : IEqualityComparer<Customer>
    {
        public bool Equals(Customer x, Customer y)
        {
            Console.WriteLine("hit!");
            return x.Id == y.Id && x.Name.Contains(y.Name);
        }

        public int GetHashCode(Customer obj)
        {
            return obj.Id.GetHashCode() ^ obj.Name.GetHashCode();
        }
    }

    public static void Main()
    {
        List<Customer> customers = new List<Customer>()
        {
            new Customer() { Id = "1234", Name = "smith" },
            new Customer() { Id = "1234", Name = "mit" }
        };
        var hashset = new HashSet<Customer>(customers, new CustomerComparer());
        var found = hashset.Contains(new Customer { Id = "1234", Name = "mit" }); // "mit" instead of an equals "smith" in the comparer.
        Console.WriteLine(found); // = true
    }
}

但是,如果您从 "customers" 列表中删除第二项,则不会命中 Equals 方法,因为列表中 "smith" 客户的哈希码与列表中的客户的哈希码不同"smith" 您传递给 Contains 方法的客户:

List<Customer> customers = new List<Customer>()
        {
            new Customer() { Id = "1234", Name = "smith" }
        };