簡體   English   中英

GetHashCode() 用於依賴 OrdinalIgnoreCase 的字符串類

[英]GetHashCode() for OrdinalIgnoreCase-dependent string classes

public class Address{
    public string ContactName {get; private set;}
    public string Company {get; private set;}
    //...
    public string Zip {get; private set;}
}

我想實現不同地址的概念,所以我覆蓋了 Equals() 以測試所有字段中不區分大小寫的相等性(因為這些是美國地址,我使用 Ordinal 而不是 InvariantCulture 以獲得最佳性能):

public override bool Equals(Object obj){
    if (obj == null || this.GetType() != obj.GetType())
        return false;

    Address o = (Address)obj;

    return  
    (string.Compare(this.ContactName, o.ContactName, StringComparison.OrdinalIgnoreCase) == 0) &&
    (string.Compare(this.Company, o.Company, StringComparison.OrdinalIgnoreCase) == 0)
    // ...
    (string.Compare(this.Zip, o.Zip, StringComparison.OrdinalIgnoreCase) == 0)
}

我想像這樣寫一個 GetHashCode() (暫時忽略連接效率低下):

public override int GetHashCode(){
    return (this.contactName + this.address1 + this.zip).ToLowerOrdinal().GetHashCode();
}

但那不存在。 我應該用什么代替? 或者我應該只在我的 Equals() 方法中使用 InvariantCulture 嗎?

(我在想.ToLowerInvariant().GetHashCode() ,但我不是 100% 確定 InvariantCulture 不能決定相同的字符(例如重音)在另一個上下文中具有不同的含義。)

無論您在Equals()中使用什么字符串比較方法,在GetHashCode()中使用相同的方法都是有意義的。

無需創建臨時字符串來計算哈希碼。 對於StringComparison.OrdinalIgnoreCase ,使用StringComparer.OrdinalIgnoreCase.GetHashCode()

然后你需要將多個哈希碼組合成一個。 XOR 應該沒問題(因為一個人的郵政編碼不太可能是另一個人的聯系人姓名)。 然而, 純粹主義者可能不同意。

public override int GetHashCode()
{
    return StringComparer.OrdinalIgnoreCase.GetHashCode(ContactName) ^
        StringComparer.OrdinalIgnoreCase.GetHashCode(Company) ^
        // ...
        StringComparer.OrdinalIgnoreCase.GetHashCode(Zip);
}

說了這么多,我懷疑使用像 Address 這樣的復合結構作為字典的鍵是否明智。 但該原則適用於身份類型字符串。

兩個不相等的對象可以具有相同的哈希碼。 盡管兩個相等的對象不應該有不同的哈希碼。 如果您將 InvariantCulture 用於您的哈希碼,如果它是根據 OrdinalIgnoreCase 實施的,就 Equals 的約定而言,它仍然是正確的。

來自 StringComparer.OrdinalIgnoreCase 的文檔(強調我的):

http://msdn.microsoft.com/en-us/library/system.stringcomparer.ordinalignorecase.aspx

OrdinalIgnoreCase 屬性返回的 StringComparer 將要比較的字符串中的字符視為使用不變區域性的約定將其轉換為大寫,然后執行與語言無關的簡單字節比較。 當比較以編程方式生成的字符串或比較不區分大小寫的資源(如路徑和文件名)時,這是最合適的。

現在你可以使用System.HashCode

public class Address
{
    public string ContactName { get; private set; }
    public string Company { get; private set; }
    // ...
    public string Zip { get; private set; }

    public override bool Equals(object obj)
    {
        return
            obj is Address address &&
            string.Equals(ContactName, address.ContactName, StringComparison.OrdinalIgnoreCase) &&
            string.Equals(Company, address.Company, StringComparison.OrdinalIgnoreCase) &&
            // ...
            string.Equals(Zip, address.Zip, StringComparison.OrdinalIgnoreCase);
    }

    public override int GetHashCode()
    {
        var hash = new HashCode();
        hash.Add(ContactName, StringComparer.OrdinalIgnoreCase);
        hash.Add(Company, StringComparer.OrdinalIgnoreCase);
        // ...
        hash.Add(Zip, StringComparer.OrdinalIgnoreCase);
        return hash.ToHashCode();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM