2010-03-08 266 views
3

兩個.net字符串有可能具有不同的哈希值嗎?我有一個Hashtable,其中包括關鍵的「路徑」。當我遍歷表中的元素來打印它時,我可以看到密鑰存在。.NET Hashtable - 「相同」鍵,不同的哈希

但試圖查看它時,沒有匹配的元素。調試表明,我正在尋找的字符串與我提供的密鑰不同。

此代碼位於Castle Monorail項目中,使用brail作爲視圖引擎。我正在尋找的密鑰由抄網線插入這樣的:

UrlHelper.Link(node.CurrentPage.LinkText, {@params: {@path: "/Page1"}}) 

然後,在該方法中(在定製IRoutingRule):

public string CreateUrl(System.Collections.IDictionary parameters) 
{ 
    PrintDictionaryToLog(parameters); 
    string url; 
    if (parameters.Contains("path")) { 
     url = (string)parameters["path"]; 
    } 
    else { 
     return null; 
    } 
} 

鍵被輸出到日誌,但該函數返回null。我不知道這可能是.net字符串的問題,但我想這是某種編碼問題?

哦,這是單聲道運行。

根據要求,這裏是從日誌中的相關行:

2010-03-08 22:58:00,504 [7] DEBUG Knickle.Framework.Routing.PageRoute (null) - Parameters: {System.String controller=null, System.String path=Page1, System.String path=/Page1, System.String action=null, System.String area=null} 

而且,在這裏我加了線的日誌打印調用上面的代碼:

parameters.Add("path", "Page1"); 

看看在日誌中,你會注意到有兩個「路徑」鍵。調試器在表中的不同位置顯示兩個鍵。

回答

1

不應該發生。檢查尾部空格,URL轉義等。

1

根據StringComparison.Ordinal或更簡單的String.Equals等於的字符串在所有情況下將具有相同的散列碼。

2

這是GetHashCode for String的MSDN鏈接。如果它們相同,則哈希碼應該匹配,但是如果它們不相等,它們仍然可以具有相同的哈希(儘管可能性很小)。

http://msdn.microsoft.com/en-us/library/system.string.gethashcode.aspx

從文章:

如果兩個字符串對象相等時, 的GetHashCode方法返回相同 值。但是,對於每個唯一字符串值 ,沒有唯一的 哈希碼值。不同的字符串可以返回 相同的哈希碼。

0

您正在使用哪個版本的Mono?這可能是Mono中的一個錯誤,如果有錯誤報告會受到歡迎。

但是我同意塞瓦,可能原因是一些尾隨空格或分隔符或一些其他編碼問題,使字符串以某種微妙的方式不同,並導致不同的哈希值。

1

這是這條線[Castle.MonoRail.Framework.Services.DefaultUrlBuilder:397] ...

// Forces copying entries to a non readonly dictionary, preserving the original one 
parameters = new Hashtable(parameters, StringComparer.InvariantCultureIgnoreCase); 

如果移除了IEqualityComparer,問題就會消失。

如果這是一個單聲道錯誤(我認爲它是必須的),它仍然是單聲道2.10.8.1(Debian 2.10.8.1-5ubuntu1)的問題。

測試用例需要編寫和歸檔。

+0

嘿,從來沒有注意到這個答案。我不再記得這個問題出現在哪個項目中了。既然這是我後來開展的一個玩具項目,但我從未解決過這個問題。儘管如此,尼斯挖掘。 – 2013-09-07 19:10:18

-1

散列表優化查找。它計算你添加的每個鍵的散列值。然後它使用這個散列碼來快速查找元素。它是一個較舊的.NET Framework類型。它比通用字典類型慢。

字典 例

首先,你可以創建一個簡單的構造一個新的哈希表。創建時,Hashtable沒有值。我們用索引器直接賦值,索引器使用方括號[]。

Next: 該示例向Hashtable對象添加了三個整數鍵,每個鍵都有一個字符串值。

將條目添加到哈希表並顯示它們[C#]

using System; 
using System.Collections; 

class Program 
{ 
    static void Main() 
    { 
    Hashtable hashtable = new Hashtable(); 
    hashtable[1] = "One"; 
    hashtable[2] = "Two"; 
    hashtable[13] = "Thirteen"; 

    foreach (DictionaryEntry entry in hashtable) 
    { 
     Console.WriteLine("{0}, {1}", entry.Key, entry.Value); 
    } 
    } 
} 

結果

13, Thirteen 
2, Two 
1, One 

程序將顯示所有的DictionaryEntry對象從在foreach循環中的枚舉返回。 WriteLine調用包含一個格式字符串,用逗號顯示鍵/值對。

的foreach

你可以通過Hashtable中循環使用在foreach循環中的DictionaryEntry類型。您也可以獲取Keys集合並將其複製到ArrayList中。 DictionaryEntry包含兩個對象:鍵和值。

的foreach 的DictionaryEntry 包含 接下來我們看到的一些關於Hashtable中最常見和最重要的實例方法。你將要在你的Hashtable上用關鍵內容調用ContainsKey。如果找到密鑰,則此方法返回true,而不考慮值。

另外: 包含工作方式相同。我們看到一個使用帶有[]方括號的索引器的例子。使用

程序包含方法[C#]

using System; 
using System.Collections; 

class Program 
{ 
    static Hashtable GetHashtable() 
    { 
    // Create and return new Hashtable. 
    Hashtable hashtable = new Hashtable(); 
    hashtable.Add("Area", 1000); 
    hashtable.Add("Perimeter", 55); 
    hashtable.Add("Mortgage", 540); 
    return hashtable; 
    } 

    static void Main() 
    { 
    Hashtable hashtable = GetHashtable(); 

    // See if the Hashtable contains this key. 
    Console.WriteLine(hashtable.ContainsKey("Perimeter")); 

    // Test the Contains method. It works the same way. 
    Console.WriteLine(hashtable.Contains("Area")); 

    // Get value of Area with indexer. 
    int value = (int)hashtable["Area"]; 

    // Write the value of Area. 
    Console.WriteLine(value); 
    } 
} 

輸出

True 
True 
1000 

索引器是接收方括號內的自變量的屬性。該Hashtable實現索引器。它返回普通對象,所以你必須施放它們。請參閱演員部分了解更多信息。

索引 多種類型 接下來,我們添加多種類型到一個Hashtable。這裏的示例添加了字符串鍵和int鍵。每個鍵/值對都有不同的類型。你可以把它們放在同一個Hashtable中。使用多種類型[C#]

using System; 
using System.Collections; 

class Program 
{ 
    static Hashtable GetHashtable() 
    { 
    Hashtable hashtable = new Hashtable(); 

    hashtable.Add(300, "Carrot"); 
    hashtable.Add("Area", 1000); 
    return hashtable; 
    } 

    static void Main() 
    { 
    Hashtable hashtable = GetHashtable(); 

    string value1 = (string)hashtable[300]; 
    Console.WriteLine(value1); 

    int value2 = (int)hashtable["Area"]; 
    Console.WriteLine(value2); 
    } 
} 

輸出

Carrot 
1000 

此代碼可能會拋出異常

計劃。鑄造是一個微妙的操作。如果強制轉換應用於其他類型,則該語句可能會引發InvalidCastException。你可以通過使用is或as語句來避免這種情況。

鑄造 您可以避免與您的Hashtable鑄造問題。您可以使用as-operator嘗試將對象轉換爲特定的引用類型。如果演員不成功,結果將爲空。

無效 提示: 您也可以使用is-operator。該運算符根據結果返回true或false。

是 作爲 程序蒙上Hashtable的值[C#]

using System; 
using System.Collections; 
using System.IO; 

class Program 
{ 
    static void Main() 
    { 
    Hashtable hashtable = new Hashtable(); 
    hashtable.Add(400, "Blazer"); 

    // This cast will succeed. 
    string value = hashtable[400] as string; 
    if (value != null) 
    { 
     Console.WriteLine(value); 
    } 

    // This cast won't succeed, but won't throw. 
    StreamReader reader = hashtable[400] as StreamReader; 
    if (reader != null) 
    { 
     Console.WriteLine("Unexpected"); 
    } 

    // You can get the object and test it. 
    object value2 = hashtable[400]; 
    if (value2 is string) 
    { 
     Console.Write("is string: "); 
     Console.WriteLine(value2); 
    } 
    } 
} 

輸出

西裝外套 是字符串:西裝外套

隨着Hashtable中,可以減少鑄件的數量並通過使用as-operator來提高性能。這是微軟靜態分析工具FxCop給出的一個性能警告。

的FxCop * 鍵,值 * 接下來,我們得到的所有鍵或值的。我們可以遍歷這些值,或將它們存儲在單獨的ArrayList集合中。此示例顯示所有鍵,然後顯示所有值,然後將鍵存儲在ArrayList中。

說明: 此C#Hashtable示例使用Keys屬性。該屬性返回所有密鑰。

遍歷鍵,值和存儲在ArrayList的[C#]

using System; 
using System.Collections; 

class Program 
{ 
    static void Main() 
    { 
    Hashtable hashtable = new Hashtable(); 
    hashtable.Add(400, "Blaze"); 
    hashtable.Add(500, "Fiery"); 
    hashtable.Add(600, "Fire"); 
    hashtable.Add(800, "Immolate"); 

    // Display the keys. 
    foreach (int key in hashtable.Keys) 
    { 
     Console.WriteLine(key); 
    } 

    // Display the values. 
    foreach (string value in hashtable.Values) 
    { 
     Console.WriteLine(value); 
    } 

    // Put keys in an ArrayList. 
    ArrayList arrayList = new ArrayList(hashtable.Keys); 
    foreach (int key in arrayList) 
    { 
     Console.WriteLine(key); 
    } 
    } 
} 

輸出

800  (First loop) 
600 
500 
400 
Immolate (Second loop) 
Fire 
Fiery 
Blaze 
800  (Third loop) 
600 
500 
400 

循環以上的密鑰。程序中的第一個循環遍歷由Hashtable實例上Keys實例屬性返回的集合。您可以使用foreach循環獲取最簡單的語法。

循環顯示值。程序中的第二個循環顯示如何僅枚舉Hashtable實例中的值。存儲在Hashtable中的四個字作爲值將被打印到屏幕上。

Console.WriteLine 存儲在ArrayList中。該示例使用複製構造函數創建一個新的ArrayList,並將Keys(或Values)屬性作爲參數傳遞給它。在ArrayList構造函數執行後,ArrayList可以被枚舉。

的ArrayList

提示: 鍵和值的公共訪問器在被訪問時返回Hashtable的鍵和值的集合。

但是: 如果您需要成對查看所有的鍵和值,最好枚舉Hashtable實例本身。

計數,清除

你可以指望在Count屬性哈希表的元素。該示例還顯示了使用Clear方法擦除所有Hashtable內容。另一種方法是將你的Hashtable引用重新分配給一個新的Hashtable()。

注意: 此示例顯示如何使用Count屬性。該屬性返回元素的數量。使用計數對哈希表

方案[C#]

using System; 
using System.Collections; 

class Program 
{ 
    static void Main() 
    { 
    // Add four elements to Hashtable. 
    Hashtable hashtable = new Hashtable(); 
    hashtable.Add(1, "Sandy"); 
    hashtable.Add(2, "Bruce"); 
    hashtable.Add(3, "Fourth"); 
    hashtable.Add(10, "July"); 

    // Get Count of Hashtable. 
    int count = hashtable.Count; 
    Console.WriteLine(count); 

    // Clear the Hashtable. 
    hashtable.Clear(); 

    // Get Count of Hashtable again. 
    Console.WriteLine(hashtable.Count); 
    } 
} 

輸出

4 
0 

首先,程序增加了四個鍵與四個值到哈希表實例。然後它捕獲Count,它是4.然後在Hashtable上使用Clear,它現在有0個元素。哈希表爲空,但不爲空。

計算Hashtable上的屬性。 Hashtable類實現一個公共實例屬性訪問器,該訪問器返回Hashtable中元素的數量。 Count屬性不執行冗長的計算或循環。

注意: MSDN指出,對於Count,「檢索此屬性的值是O(1)操作。」

恆定時間。該屬性是一個常量訪問器。它會報告一個Hashtable在其桶(或零)中有幾個實際元素。它返回一個整數並且是一個資源需求低的簡單訪問器。

基準

繼續,我們在打擊System.Collections.Generic命名空間的字典集合System.Collections命名空間測試HashTable集合。基準首先填充每個集合的同等版本。

Then: 它測試一個找到的鍵和一個找不到的鍵。它重複這2000萬次。在基準測試[C#]使用

哈希表的20000000個查找

Hashtable result: 966 ms 
Dictionary result: 673 ms 

哈希表代碼

Hashtable hashtable = new Hashtable(); 
for (int i = 0; i < 10000; i++) 
{ 
    hashtable[i.ToString("00000")] = i; 
} 

Dictionary used in benchmark [C#] 

var dictionary = new Dictionary<string, int>(); 
for (int i = 0; i < 10000; i++) 
{ 
    dictionary.Add(i.ToString("00000"), i); 
} 

Statements benchmarked [C#] 

hashtable.ContainsKey("09999") 
hashtable.ContainsKey("30000") 

dictionary.ContainsKey("09999") 
dictionary.ContainsKey("30000") 

基準比字典碼顯著慢。我計算出這裏的Hashtable慢了30%。這意味着對於強類型集合,字典更快。

構造

有在Hashtable類15個重載構造函數。這些提供了指定容量的方法。他們讓你將現有的集合複製到Hashtable中。您還可以指定哈希代碼的計算方式。

構造提示 摘要

我們使用哈希表集合。這是由Dictionary集合廢棄的較舊的集合。在維護較舊的程序時,瞭解如何使用它至關重要。這些計劃對許多組織都很重要。

+0

我知道哈希表如何工作。即使提問,我也知道。而且,這個答案決不會試圖回答我的實際問題。另外,您從其他網站(http://www.dotnetperls.com/hashtable)複製粘貼也沒有得分。如果除了某些其他網頁所說的內容外,沒有什麼可說的,只需在該問題的評論中發佈鏈接即可。 – 2013-03-21 14:49:18