就我(想)知道,Dictionary
被实现为哈希表,其中哈希码用于标识存储桶,然后搜索该存储桶。
在我看来,这意味着一个对象的哈希码在我的程序运行期间保持稳定(松散地说)。
现在,这里
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx
我读了
“哈希代码用于在基于哈希表的集合中进行有效插入和查找。哈希代码不是永久值。因此: [...] 请勿使用哈希码作为从密钥集合中检索对象的密钥。“
有人可以向我解释这是什么意思吗?
答案 0 :(得分:5)
当文档谈到“键控集合”时,它们并不意味着与字典相同。要深入了解它的实际含义,请注意实际上有一个KeyedCollection
基类:http://msdn.microsoft.com/en-us/library/ms132438%28v=vs.110%29.aspx
关键段落是:
与字典不同,
KeyedCollection<TKey, TItem>
的元素不是键/值对;相反,整个元素是值,键嵌入在值中。例如,从Visual Basic中的KeyedCollection<String,String>
(KeyedCollection(Of String, String)
派生的集合的元素可能是“John Doe Jr.”其价值是“John Doe Jr.”关键是“Doe”;或者可以从KeyedCollection<int,Employee>
派生包含整数键的员工记录集合。抽象GetKeyForItem
方法从元素中提取密钥。
因此,键控集合是一组对象以及从每个对象中提取键的方法。从概念上讲,这类似于数据库中的表,您可以在其中定义主键,该主键是整个记录的子集。
因此,考虑到这一点,答案变得相对清晰。正如其他人所说,哈希码的相等并不意味着对象的相等性。但是,键控集合中的键(如数据库表中的主键)应唯一标识确切的对象。因此,哈希冲突的可能性使它们不适用于此目的。
此外,即使在Dictionary
中,使用对象作为键并使用相同对象的哈希码作为键也存在重要区别。如果两个对象具有哈希冲突但没有比较相等,则Dictionary
仍将它们存储为两个单独的键。这就是为什么重写GetHashCode
只返回1总是有效的(虽然显然不利于性能)。作为示范:
var dict = new Dictionary<MyClass, string>();
var hashDict = new Dictionary<int, string>();
dict[myObj1] = "One";
hashDict[myObj1.GetHashCode()] = "One";
dict[myObj2] = "Two";
hashDict[myObj2.GetHashCode()] = "Two";
Console.Out.WriteLine(dict[myObj1]); //Outputs "One"
Console.Out.WriteLine(hashDict[myObj1.GetHashCode()]); //Outputs "Two"
(myObj1
和myObj2
是MyClass
的实例,它们具有相同的哈希码,但不能比较相等)
答案 1 :(得分:3)
他们可能在谈论KeyedCollection 在这种情况下,没有使用哈希作为密钥的目的 它们的关键应该是班级使用的真实价值。
与示例中的相似
public class SimpleOrder : KeyedCollection<int, OrderItem>
{
// The parameterless constructor of the base class creates a
// KeyedCollection with an internal dictionary. For this code
// example, no other constructors are exposed.
//
public SimpleOrder() : base() {}
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items. The input parameter type is the
// second generic type argument, in this case OrderItem, and
// the return value type is the first generic type argument,
// in this case int.
//
protected override int GetKeyForItem(OrderItem item)
{
// In this example, the key is the part number.
return item.PartNumber;
}
}
PartNumber是OrderItem的一个属性(恰好是一个int) 您永远不应该使用Hash OrderItem作为GetKeyForItem
答案 2 :(得分:2)
我认为该特定项目所说的不是将哈希码用作键。例如,没有Dictionary<int, MyObject>
,其中整数键是哈希码。
这样做的主要原因是两个不同的项可能具有相同的哈希码。
使用哈希码的安全方法是......不要直接使用它们。也就是说,编写调用GetHashCode
的代码非常罕见。如果您的代码没有调用GetHashCode
,那么您的代码无法保存这些值,并且您不会遇到麻烦,具体取决于您不应该依赖的内容。
答案 3 :(得分:1)
documentatinon意味着在程序的连续运行之间,哈希码不受保证(甚至可能)相同。因此,如果您尝试将其用作外部数据源(如数据库或键值存储)的键,则这将不可靠。然而,使用它作为存储桶表的索引的基础(在字典中的内存中) 正是它为其设计的。
答案 4 :(得分:1)
这解释了它:
.NET Framework不保证默认实现 GetHashCode方法,此方法返回的值可能不同 .NET Framework版本和平台之间,例如32位和 64位平台。
每次在同一环境中运行程序时,您可能总是获得相同的哈希码,但如果您在不同平台或不同版本的.net框架上运行相同的程序,则无法保证哈希值代码将是相同的。