2010-03-08 96 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