C# 为什么我不能在IEqualityComparer中使用customer.Name.contains(";smith";)lt;客户>;相等法

C# 为什么我不能在IEqualityComparer中使用customer.Name.contains(";smith";)lt;客户>;相等法,c#,iequalitycomparer,C#,Iequalitycomparer,我想使用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. var hashset=n

我想使用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.
var hashset=newhashset(customers,newcustomercomparer());
var found=hashset.Contains(新客户{Id=“1234”,Name=“mit”});//“mit”而不是比较器中的“smith”。
我正在搜索customer对象上的多个属性

我必须实现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();
    }
}
公共类客户比较:IEqualityComparer
{
公共布尔等于(客户x、客户y)
{
返回x.Id==y.Id&&x.Name.Contains(y.Name);
}      
public int GetHashCode(客户对象)
{
返回obj.Id.GetHashCode()^obj.Name.GetHashCode();
}
}

如果我没有在CustomerComparer Equals方法中使用Equals方法,例如.Contains,那么为什么Equals方法从未命中?

您实现equality comparer的方式无法正常工作。原因是哈希集和相等比较器在内部的工作方式。当
字典
哈希集
对项目进行比较时,它将首先对这两个项目调用
GetHashCode
。只有当这些哈希代码匹配时,它才会通过后续调用
Equals
来确认精确匹配,以避免哈希代码冲突时出现错误匹配。如果使用示例(
x.Name=“smith”
y.Name=“mit”
),则
GetHashCode
方法将为每个项返回不同的哈希代码,并且永远不会调用
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));
}      

您实现相等比较器的方式无法正常工作。原因是哈希集和相等比较器在内部的工作方式。当
字典
哈希集
对项目进行比较时,它将首先对这两个项目调用
GetHashCode
。只有当这些哈希代码匹配时,它才会通过后续调用
Equals
来确认精确匹配,以避免哈希代码冲突时出现错误匹配。如果使用示例(
x.Name=“smith”
y.Name=“mit”
),则
GetHashCode
方法将为每个项返回不同的哈希代码,并且永远不会调用
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));
}      
为什么当我没有在CustomerComparer Equals方法(如.Contains)中使用Equals方法时,Equals方法从未命中

只有在“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
    }
}
公共静态类程序
{
公共类客户
{
公共字符串Id{get;set;}
公共字符串名称{get;set;}
}
公共类客户比较:IEqualityComparer
{
公共布尔等于(客户x、客户y)
{
控制台。WriteLine(“命中!”);
返回x.Id==y.Id&&x.Name.Contains(y.Name);
}
public int GetHashCode(客户对象)
{
返回obj.Id.GetHashCode()^obj.Name.GetHashCode();
}
}
公共静态void Main()
{
列出客户=新列表()
{
新客户(){Id=“1234”,Name=“smith”},
新客户(){Id=“1234”,Name=“mit”}
};
var hashset=new hashset(客户,new CustomerComparer());
var found=hashset.Contains(新客户{Id=“1234”,Name=“mit”});//“mit”,而不是比较器中的等于“smith”。
Console.WriteLine(已找到);/=true
}
}
但如果从“客户”列表中删除第二项,则不会命中Equals方法,因为列表中“smith”客户的哈希代码与传递给Contains方法的“smith”客户的哈希代码不同:

List<Customer> customers = new List<Customer>()
        {
            new Customer() { Id = "1234", Name = "smith" }
        };
列出客户=新列表()
{
新客户(){Id=“1234”,Name=“smith”}
};
为什么当我没有在CustomerComparer Equals方法(如.Contains)中使用Equals方法时,Equals方法从未命中

只有在“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
    }
}
公共静态类程序
{
公共类客户
{
公共字符串Id{get;set;}
公共字符串名称{get;set;}
}
公共类客户比较:IEqualityComparer
{
公共布尔等于(客户x、客户y)
{
控制台。WriteLine(“命中!”);
返回x.Id==y.Id&&x.Name.Contains(y.Name);
}
public int GetHashCode(客户对象)
{
返回obj.Id.GetHashCode()^obj.Name.GetHashCode();
}
}
P