2009-06-05 51 views
13

我在C#中的地址類,看起來像這樣:我應該用我的字符串字段的串聯的散列碼?

public class Address 
{    
    public string StreetAddress { get; set; } 
    public string RuralRoute { get; set; } 
    public string City { get; set; } 
    public string Province { get; set; } 
    public string Country { get; set; } 
    public string PostalCode { get; set; } 
} 

我實現平等,所以我需要重寫的哈希碼。起初,我打算用從EJ的哈希碼公式,但轉念一想:這些都是字符串字段,我不能只是只使用StringBuilder將它們串聯,並從該字符串返回的哈希碼?

即:

var str = new StringBuilder(); 
str.Append(StreetAddress) 
    .Append(RuralRoute) 
    ... 

return str.ToString().GetHashCode(); 

這有什麼優勢/劣勢?爲什麼我不應該這樣做呢?

+1

供大家參考:http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-systemobjectgethashcode – lance 2009-06-05 19:16:20

回答

14

我會避免這樣做,只是因爲它會毫無意義地創建一串字符串 - 儘管Kosi2801關於簡化碰撞的觀點也很重要。 (我懷疑它不會實際上創造了許多衝突,由於場的性質,但是......)

我會去的「簡單易得的權利」的算法我以前used in this answer (感謝尋找它槍:) - 而這是在有效的Java上市,如你所說。在這種情況下,它將最終爲:

public int GetHashCode() 
{ 
    int hash = 17; 
    // Suitable nullity checks etc, of course :) 
    hash = hash * 23 + StreetAddress.GetHashCode(); 
    hash = hash * 23 + RuralRoute.GetHashCode(); 
    hash = hash * 23 + City.GetHashCode(); 
    hash = hash * 23 + Province.GetHashCode(); 
    hash = hash * 23 + Country.GetHashCode(); 
    hash = hash * 23 + PostalCode.GetHashCode(); 
    return hash; 
} 

這當然不是無效的。如果您使用C#3你可能要考慮的擴展方法:

public static int GetNullSafeHashCode<T>(this T value) where T : class 
{ 
    return value == null ? 1 : value.GetHashCode(); 
} 

然後你可以使用:

public int GetHashCode() 
{ 
    int hash = 17; 
    // Suitable nullity checks etc, of course :) 
    hash = hash * 23 + StreetAddress.GetNullSafeHashCode(); 
    hash = hash * 23 + RuralRoute.GetNullSafeHashCode(); 
    hash = hash * 23 + City.GetNullSafeHashCode(); 
    hash = hash * 23 + Province.GetNullSafeHashCode(); 
    hash = hash * 23 + Country.GetNullSafeHashCode(); 
    hash = hash * 23 + PostalCode.GetNullSafeHashCode(); 
    return hash; 
} 

可以創建參數數組方法工具來使這個更簡單:

public static int GetHashCode(params object[] values) 
{ 
    int hash = 17; 
    foreach (object value in values) 
    { 
     hash = hash * 23 + value.GetNullSafeHashCode(); 
    } 
    return hash; 
} 

,並稱之爲:

public int GetHashCode() 
{ 
    return HashHelpers.GetHashCode(StreetAddress, RuralRoute, City, 
            Province, Country, PostalCode); 
} 

在大多數類型有涉及原語,讓本來有些不必要的執行拳擊,但在這種情況下,你只需要引用。當然,你最終會不必要地創建一個數組,但你知道他們說的過早的優化是什麼?

+1

另一種解決方案是使用EqualityComparer 。 Default.GetHashCode(someValue中)。這是一個空的安全散列機制,並且自2.0開始在框架中 – JaredPar 2009-06-05 19:28:27

5

不要這樣做,因爲儘管哈希碼是相同的,但對象可以不同。

思考的

"StreetAddress" + "RuralRoute" + "City" 

VS

"Street" + "AddressRural" + "RouteCity" 

雙方將有相同的散列碼,但在不同領域的內容。

+0

,這是一個很好的點,我本來連認爲。儘管在實踐中似乎不太可能發生。 – cdmckay 2009-06-05 19:34:47

+1

Coulnd't很容易通過在字段之間放置分隔符來解決? (例如``StreetAddress「+」/ delimiter /「+」RuralRoute「+」/ delimiter /「+」City「`。可能是一個變量以避免某些語言中的多重賦值) – simonra 2016-11-23 08:01:25

0

對於這樣的事情,你可能想實現IEqualityComparer<Address>

public class Address : IEqualityComparer<Address> 
{   
    // 
    // member declarations 
    // 

    bool IEqualityComparer<Address>.Equals(Address x, Address y) 
    { 
     // implementation here 
    } 

    int IEqualityComparer<Address>.GetHashCode(Item obj) 
    { 
     // implementation here 
    } 
} 

你還可以實現IComparable<Address>拿到訂購...

-4
public string getfourDigitEncryptedText(string input) { 
    int hashCode = input.hashCode(); 
    string hstring = (new StringBuilder()).append(hashCode).append("").toString(); 
    string rev_hstring = (new StringBuilder(hstring)).reverse().toString(); 
    string parts[] = rev_hstring.trim().split(""); 
    int prefixint = 0; 
    for(int i = 1; i <= parts.length - 3; i++) 
     prefixint += integer.parseInt(parts[i]); 
    string prefixstr = "0"; 
    if((new integer(prefixint)).toString().length() < 2) 
     prefixstr = (new StringBuilder()).append((new integer(prefixint)).toString()).append("5").toString(); 
    else if((new integer(prefixint)).toString().length() > 2) 
     prefixstr = "79"; 
    else 
     prefixstr = (new integer(prefixint)).toString(); 
    string finalstr = (new StringBuilder()).append(prefixint).append(rev_hstring.substring(3, 5)).toString(); 
    return finalstr; 
} 
相關問題