2015-06-08 27 views
1

我有兩個不同的對象列表,並希望根據某些屬性的權重獲得它們的相似性。最快的方法似乎是實現了IEquatable接口,這就是我做:在比較兩個對象時有條件地更改GetHashCode()

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? 或者有沒有辦法用其他方式進行相似性檢查?

+2

「Equals」的正確實現必須具有如果A等於B且B等於C,那麼A等於C的屬性。我不確定您的「Equals」實現是否具有該屬性。而當一個實現缺少這個屬性時,你經常會爲創建一個正確實現'GetHashCode'而努力,而這正是你所經歷的。 –

+0

你真的不應該重寫'Equals()'來做模糊匹配,當它傳遞給一個Sort時,它會打破各種契約,比如[及物性](http://en.wikipedia.org/wiki/Transitive_relation) ()'方法。 – Phylogenesis

+0

爲什麼你不能在一個單獨的方法中計算對象的權重,然後在GetHashCode()中使用該方法的輸出? 但是請注意,GetHashCode並不是爲了比較對象的相等性,它只是提供了字典中散列算法的提示和類似的實現來散列對象在散列表 –

回答

5

Equals/GetHashCode並非設計用於比較「大致相等」的事物。在這種情況下,平等只是布爾屬性。特別是,具有模糊的「大致相等」的方法會導致傳遞性問題。的Object.Equals的載文包括這個需求量的:

如果(x.Equals(y) && y.Equals(z))回報true,然後x.Equals(z)回報true

當你有模糊相等時,這根本不成立。只是因爲x是「很像」yy是「非常喜歡」z並不意味着x是「非常喜歡」z

現在你可以做的是有一個只比較電話號碼的相等比較器,另一個只比較名稱的相等比較器等 - 但這不會真正讓你模糊匹配。