2013-03-01 26 views
0

通過搜索雖然MSDN C#的文件和堆棧溢出,我得到了清晰的印象是Dictionary<T,T>應該使用GetHashCode()檢查密鑰的唯一性和做查找。單執行字典<T,T>使用.Equals的(OBJ O)代替.GetHashCode()

Dictionary泛型類提供了從一組鍵到一組值的映射。字典中的每個添加項都包含一個值及其關聯的鍵。使用其鍵值檢索值非常快,接近O(1),因爲Dictionary類是作爲散列表實現的。 ... 檢索速度取決於爲TKey指定的類型的哈希算法的質量。當使用

public class DictionaryTest 
{ 
    public static void TestKeyUniqueness() 
    { 
    //Test a dictionary of type1 
    Dictionary<KeyType1, string> dictionaryType1 = new Dictionary<KeyType1, string>(); 
    dictionaryType1[new KeyType1(1)] = "Val1"; 
    if(dictionaryType1.ContainsKey(new KeyType1(1))) 
    { 
     Debug.Log ("Key in dicType1 was already present"); //This line does NOT print 
    } 

    //Test a dictionary of type1 
    Dictionary<KeyType2, string> dictionaryType2 = new Dictionary<KeyType2, string>(); 
    dictionaryType2[new KeyType2(1)] = "Val1"; 
    if(dictionaryType2.ContainsKey(new KeyType2(1))) 
    { 
     Debug.Log ("Key in dicType2 was already present"); // Only this line prints 
    } 
    } 
} 
//This type implements only GetHashCode() 
public class KeyType1 
{ 
    private int var1; 

    public KeyType1(int v1) 
    { 
     var1 = v1; 
    } 

    public override int GetHashCode() 
    { 
     return var1; 
    } 
} 
//This type implements both GetHashCode() and Equals(obj), where Equals uses the hashcode. 
public class KeyType2 
{ 
    private int var1; 

    public KeyType2(int v1) 
    { 
     var1 = v1; 
    } 

    public override int GetHashCode() 
    { 
     return var1; 
    } 

    public override bool Equals (object obj) 
    { 
     return GetHashCode() == obj.GetHashCode(); 
    } 
} 

只有:

我使用單(在Unity3D),並得到了一些奇怪的結果在我的工作後,我進行了這項實驗類型KeyType2是被認爲相同的關鍵。對我來說,這表明Dictionary使用Equals(obj) - 而不是GetHashCode()。

有人可以重現這一點,並幫助我解釋的意思是?這是單聲道不正確的實現嗎?或者我誤解了一些東西。

回答

2

我得到的明確印象是詞典應該使用 .GetHashCode()檢查關鍵唯一性

是什麼讓你認爲? GetHashCode不返回唯一值。

而且MSDN清清楚楚地寫着:

字典需要一個平等的實現來 確定鍵是否相等。您可以通過使用 接受比較器參數的構造函數指定IEqualityComparer通用接口的實現: ;如果您未指定實現,則使用 默認通用相等比較器EqualityComparer.Default爲 。如果類型TKey實現System.IEquatable通用接口,則默認的相等比較器將使用該實現。

+0

MSDN還聲明: 「Dictionary 泛型類提供了從一組鍵到一組值的映射。由一個值及其相關的鍵組成,使用它的鍵檢索值非常快,接近於O(1),因爲Dictionary 類是作爲散列表實現的。「 我把它解釋爲這意味着散列用於唯一性和查找。 – sune 2013-03-01 11:39:37

+0

@sune它僅用於查找。正如名字所說,'GetHasCode'只是一個幫助排序項目以加快查找的散列。有關'GetHashCode'的用法,請參閱http://stackoverflow.com/questions/7425142/what-is-hashcode-use-for-is-it-unique。 – ken2k 2013-03-01 12:24:25

+0

感謝您的回答。 – sune 2013-03-01 12:30:58

1

這樣做:

public override bool Equals (object obj) 
{ 
    return GetHashCode() == obj.GetHashCode(); 
} 

是錯在一般情況下,因爲你可能最終與KeyType2實例是相等StringBuilderSomeOtherClassAnythingYouCanImagine並沒有什麼情況。

你應該完全做到這一點,像這樣:

public override bool Equals (object obj) 
{ 
    if (obj is KeyType2) { 
     return (obj as KeyType2).var1 == this.var1; 
    } else 
     return false; 
} 

當你在這個順序試圖重寫Equals和固有GetHashCode你必須確保以下幾點(給定類的MyObject)(你在做它相反):

1)MyObject的兩個實例的時間是否相等?假設您有:

public class MyObject { 
    public string Name { get; set; } 
    public string Address { get; set; } 
    public int Age { get; set; } 

    public DateTime TimeWhenIBroughtThisInstanceFromTheDatabase { get; set; } 
} 

而且您在某些數據庫中有1條記錄需要映射到此類的實例。 而你讓你從數據庫中讀取記錄的時間將被存儲 在TimeWhenIBroughtThisInstanceFromTheDatabase約定:

MyObject obj1 = DbHelper.ReadFromDatabase(...some params...); 
// you do that at 14:05 and thusly the TimeWhenIBroughtThisInstanceFromTheDatabase 
// will be assigned accordingly 

// later.. at 14:07 you read the same record into a different instance of MyClass 
MyObject obj2 = DbHelper.ReadFromDatabase(...some params...); 
// (the same) 

// At 14:09 you ask yourself if the 2 instances are the same 
bool theyAre = obj1.Equals(obj2) 

你想要得到的結果是真正?我會說你這樣做。 因此的Equals的首要謹這樣:

public class MyObject { 
    ... 
    public override bool Equals(object obj) { 
     if (obj is MyObject) { 
      var that = obj as MyObject; 
      return (this.Name == that.Name) && 
        (this.Address == that.Address) && 
        (this.Age == that.Age); 
        // without the syntactically possible but logically challenged: 
        // && (this.TimeWhenIBroughtThisInstanceFromTheDatabase == 
        //  that.TimeWhenIBroughtThisInstanceFromTheDatabase) 
     } else 
      return false; 
    } 
    ... 
} 

2)。確保每當2個實例是相等的(由Equals方法所指示的要實現) 其GetHashCode的結果將identitcal。

int hash1 = obj1.GetHashCode(); 
int hash2 = obj2.GetHashCode(); 
bool theseMustBeAlso = hash1 == hash2; 

做到這一點的最簡單的方法是(在示例場景):

public class MyObject { 
    ... 
    public override int GetHashCode() { 
     int result; 
     result = ((this.Name != null) ? this.Name.GetHashCode() : 0)^
       ((this.Address != null) ? this.Address.GetHashCode() : 0)^
       this.Age.GetHashCode(); 
     // without the syntactically possible but logically challenged: 
     //^this.TimeWhenIBroughtThisInstanceFromTheDatabase.GetHashCode() 
    } 
    ... 
} 

注意: - 字符串可以爲空,並且.GetHashCode()可能失敗,NullReferenceException。 - 我用^(XOR)。只要遵守黃金法則(數字2),就可以使用任何你想要的東西。 (字符串類型){ - x^0 == x(對於任何x)

+0

感謝您的回答。很明顯,你實現Equals和GetHashCode的方式比我的更正確。我的代碼只是爲了測試Dictionary 是否使用了GetHashCode()。它似乎不是。 – sune 2013-03-01 11:57:46

相關問題