哈希码作为键集合中的键

本文关键字:集合 哈希码 | 更新日期: 2023-09-27 18:06:38

据我所知,Dictionary是作为哈希表实现的,其中哈希码用于标识桶,然后在桶中搜索键。

在我看来,这意味着对象的哈希码在我的程序的单次运行期间保持稳定(粗略地说)。

现在,这里

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

我读

"哈希码用于在基于哈希表的集合中进行有效的插入和查找。哈希码不是永久值。出于这个原因:[…]

谁能给我解释一下这是什么意思?

哈希码作为键集合中的键

当文档谈到"键集合"时,它们的意思与Dictionary不同。要深入了解它的实际含义,请注意实际上有一个KeyedCollection基类:http://msdn.microsoft.com/en-us/library/ms132438%28v=vs.110%29.aspx

关键段落是:

与字典不同,KeyedCollection<TKey, TItem>的元素不是键/值对;相反,整个元素就是值,键被嵌入到值中。例如,从KeyedCollection<String,String> (Visual Basic中的(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"

(myObj1myObj2MyClass的实例,它们具有相同的哈希码,但不比较为相等)

他们可能在谈论KeyedCollection。
在这种情况下,没有必要使用散列作为键。
key应该是类使用的实值。

输入链接描述

如示例

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型)的一个属性
你永远不应该使用hashorderitem作为GetKeyForItem

我认为该特定项的意思是不使用哈希码作为密钥。例如,不要有Dictionary<int, MyObject>,其中的整数键是哈希码。

这样做的主要原因是两个不同的项可能具有相同的哈希码。

使用哈希码的安全方法是…不要直接使用。也就是说,很少会编写调用GetHashCode的代码。如果你的代码不调用GetHashCode,那么你的代码就不能保存值,你就不能因为你不应该依赖的东西而陷入麻烦。

说明:

.NET框架不保证GetHashCode方法,并且该方法返回的值可能不同.NET框架版本和平台之间的差异,例如32位和平台64位平台。

每次你在相同的环境中运行你的程序,你可能总是得到相同的哈希码,但如果你在不同的平台或不同版本的。net框架上运行相同的程序,不能保证哈希码是相同的。

文档说明不保证(甚至不可能)在程序的连续运行之间是相同的哈希码。因此,如果您尝试将其用作指向外部数据源(如数据库或键值存储)的键,那么这将不可靠。然而,使用作为桶表索引的基础(在内存中,就像在字典中一样)正是的设计目的。