比较两个对象时有条件地更改 GetHashCode()
Conditionally change GetHashCode() when comparing two objects
我有两个不同的对象列表,想根据某些属性的权重获得它们的相似性。最快的方法似乎是实现一个 IEquatable 接口,这就是我所做的:
public class CompareEntry : IEquatable<CompareEntry>
{
public int LeadId { get; set; }
public int SaleId { get; set; }
public string Email { get; set; }
public string PhonePrivate { get; set; }
public string PhoneMobile { get; set; }
public string PhoneCompany { get; set; }
public string FirstName { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string CompanyName { get; set; }
public bool Equals(CompareEntry other)
{
int weight = 0;
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null))
{
return false;
}
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other))
{
return true;
}
if ((this.CheckProperties(this.Email, other.Email) && this.Email == other.Email)
|| (this.CheckProperties(this.PhonePrivate, other.PhonePrivate) && this.PhonePrivate == other.PhonePrivate)
|| (this.CheckProperties(this.PhoneMobile, other.PhoneMobile) && this.PhoneMobile == other.PhoneMobile)
|| (this.CheckProperties(this.PhoneCompany, other.PhoneCompany) && this.PhoneCompany == other.PhoneCompany))
{
weight += 100;
}
if ((this.CheckProperties(this.Name, other.Name) && this.Name == other.Name)
|| (this.CheckProperties(this.FirstName, other.FirstName) && this.FirstName == other.FirstName))
{
weight += 25;
}
if ((this.CheckProperties(this.City, other.City) && this.City == other.City)
|| (this.CheckProperties(this.ZipCode, other.ZipCode) && this.ZipCode == other.ZipCode))
{
weight += 12;
}
if (this.CheckProperties(this.CompanyName, other.CompanyName) && this.CompanyName == other.CompanyName)
{
weight += 5;
}
return weight > 50;
}
public override int GetHashCode()
{
unchecked
{
int hash = (int)2166136261;
hash = hash * 16777619 ^ (string.IsNullOrEmpty(Email) ? 0 : Email.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(PhonePrivate) ? 0 : PhonePrivate.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(PhoneMobile) ? 0 : PhoneMobile.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(PhoneCompany) ? 0 : PhoneCompany.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(FirstName) ? 0 : FirstName.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(Name) ? 0 : Name.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(City) ? 0 : City.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(ZipCode) ? 0 : ZipCode.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(CompanyName) ? 0 : CompanyName.GetHashCode());
return hash;
}
}
private bool CheckProperties(string prop, string otherProp)
{
return !string.IsNullOrEmpty(prop) && !string.IsNullOrEmpty(otherProp);
}
}
问题是,当我重写 GetHashCode() 方法时,我只得到那些完全相同的人,或者在这种特殊情况下 - 只得到相同的电子邮件。
如何在 GetHashCode() 方法中有条件地检查权重,以便我可以使用更正方法 Equals?
或者有没有办法用其他方式进行相似性检查,性能好吗?
Equals
/ GetHashCode
并非旨在比较 "mostly equal" 的事物。在这种情况下,相等只是一个布尔值 属性。特别是,使用模糊 "mostly equal" 方法会导致传递性问题。 Object.Equals
的文档包括此要求:
If (x.Equals(y) && y.Equals(z))
returns true
, then x.Equals(z)
returns true
.
当你有模糊相等时,这根本不成立。仅仅因为 x
是 "quite like" y
并且 y
是 "quite like" z
并不意味着 x
是 "quite like" z
.
现在你 可以 做的是有一个只比较 phone 数字的相等比较器,另一个只比较名称的相等比较器,等等 - 但那不会真正让你模糊匹配。
我有两个不同的对象列表,想根据某些属性的权重获得它们的相似性。最快的方法似乎是实现一个 IEquatable 接口,这就是我所做的:
public class CompareEntry : IEquatable<CompareEntry>
{
public int LeadId { get; set; }
public int SaleId { get; set; }
public string Email { get; set; }
public string PhonePrivate { get; set; }
public string PhoneMobile { get; set; }
public string PhoneCompany { get; set; }
public string FirstName { get; set; }
public string Name { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
public string CompanyName { get; set; }
public bool Equals(CompareEntry other)
{
int weight = 0;
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null))
{
return false;
}
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other))
{
return true;
}
if ((this.CheckProperties(this.Email, other.Email) && this.Email == other.Email)
|| (this.CheckProperties(this.PhonePrivate, other.PhonePrivate) && this.PhonePrivate == other.PhonePrivate)
|| (this.CheckProperties(this.PhoneMobile, other.PhoneMobile) && this.PhoneMobile == other.PhoneMobile)
|| (this.CheckProperties(this.PhoneCompany, other.PhoneCompany) && this.PhoneCompany == other.PhoneCompany))
{
weight += 100;
}
if ((this.CheckProperties(this.Name, other.Name) && this.Name == other.Name)
|| (this.CheckProperties(this.FirstName, other.FirstName) && this.FirstName == other.FirstName))
{
weight += 25;
}
if ((this.CheckProperties(this.City, other.City) && this.City == other.City)
|| (this.CheckProperties(this.ZipCode, other.ZipCode) && this.ZipCode == other.ZipCode))
{
weight += 12;
}
if (this.CheckProperties(this.CompanyName, other.CompanyName) && this.CompanyName == other.CompanyName)
{
weight += 5;
}
return weight > 50;
}
public override int GetHashCode()
{
unchecked
{
int hash = (int)2166136261;
hash = hash * 16777619 ^ (string.IsNullOrEmpty(Email) ? 0 : Email.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(PhonePrivate) ? 0 : PhonePrivate.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(PhoneMobile) ? 0 : PhoneMobile.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(PhoneCompany) ? 0 : PhoneCompany.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(FirstName) ? 0 : FirstName.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(Name) ? 0 : Name.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(City) ? 0 : City.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(ZipCode) ? 0 : ZipCode.GetHashCode());
//hash = hash * 16777619 ^ (string.IsNullOrEmpty(CompanyName) ? 0 : CompanyName.GetHashCode());
return hash;
}
}
private bool CheckProperties(string prop, string otherProp)
{
return !string.IsNullOrEmpty(prop) && !string.IsNullOrEmpty(otherProp);
}
}
问题是,当我重写 GetHashCode() 方法时,我只得到那些完全相同的人,或者在这种特殊情况下 - 只得到相同的电子邮件。
如何在 GetHashCode() 方法中有条件地检查权重,以便我可以使用更正方法 Equals? 或者有没有办法用其他方式进行相似性检查,性能好吗?
Equals
/ GetHashCode
并非旨在比较 "mostly equal" 的事物。在这种情况下,相等只是一个布尔值 属性。特别是,使用模糊 "mostly equal" 方法会导致传递性问题。 Object.Equals
的文档包括此要求:
If
(x.Equals(y) && y.Equals(z))
returnstrue
, thenx.Equals(z)
returnstrue
.
当你有模糊相等时,这根本不成立。仅仅因为 x
是 "quite like" y
并且 y
是 "quite like" z
并不意味着 x
是 "quite like" z
.
现在你 可以 做的是有一个只比较 phone 数字的相等比较器,另一个只比较名称的相等比较器,等等 - 但那不会真正让你模糊匹配。