为什么我不能在 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 方法永远不会命中?
您实现相等比较器的方式无法正常工作。原因是散列集和相等比较器在内部是如何工作的。当 Dictionary
或 HashSet
对项目进行比较时,它将首先对两个项目调用 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" }
};
我想使用 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 方法永远不会命中?
您实现相等比较器的方式无法正常工作。原因是散列集和相等比较器在内部是如何工作的。当 Dictionary
或 HashSet
对项目进行比较时,它将首先对两个项目调用 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" }
};