.net 字典中的哈希代码<;TKey,TValue>;

.net 字典中的哈希代码<;TKey,TValue>;,.net,dictionary,hashcode,.net,Dictionary,Hashcode,我在玩字典,无意中发现了下面的场景 public class MyObject { public string I { get; set; } public string J { get; set; } public string K { get; set; } public override int GetHashCode() { int hashCode = (I+J+K).GetHashCode(); Debugge

我在玩字典,无意中发现了下面的场景

public class MyObject
{
    public string I { get; set; }
    public string J { get; set; }
    public string K { get; set; }

    public override int GetHashCode()
    {
        int hashCode = (I+J+K).GetHashCode();
        Debugger.Log(9, "INFO", hashCode.ToString() + System.Environment.NewLine);
        return hashCode;
    }
}
class Program
{
    static void Main(string[] args)
    {
        MyObject obj1 = new MyObject() { I = "Hello", J = "World" };
        MyObject obj2 = new MyObject() { I = "Hello", J = "World" };

        Dictionary<MyObject, string> collection = new Dictionary<MyObject, string>();
        collection.Add(obj1, "1");
        var result = collection[obj2]; // KeyNotFound exception here.
    }
}
公共类MyObject
{
公共字符串I{get;set;}
公共字符串J{get;set;}
公共字符串K{get;set;}
公共覆盖int GetHashCode()
{
int hashCode=(I+J+K).GetHashCode();
Log(9,“INFO”,hashCode.ToString()+System.Environment.NewLine);
返回哈希码;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
MyObject obj1=新的MyObject(){I=“Hello”,J=“World”};
MyObject obj2=newmyobject(){I=“Hello”,J=“World”};
字典集合=新字典();
集合。添加(obj1,“1”);
var result=collection[obj2];//此处发现KeyNotFound异常。
}
}
我有一个MyObject类,它充当dictionary的键,我重写GetHashCode方法,根据类中存储的值返回哈希代码

因此,当执行上述代码时,obj1和obj2都返回相同的哈希代码,但字典仍然抛出KeyNotFound异常

为什么会有这样的行为?

您需要覆盖

Dictionary
和其他基于散列的集合将散列相等视为完全相等的必要但不充分的条件,因为可能存在散列冲突。在您的示例中,key getter找到了要搜索的正确哈希桶,甚至将
obj1
视为完全相等的候选,但由于
Equals
的默认实现基于引用相等,因此被拒绝

理想情况下,在课堂上实施
IEquatable

public class MyObject : IEquatable<MyObject>
{
    public string I { get; set; }
    public string J { get; set; }
    public string K { get; set; }

    public override int GetHashCode()
    {
        // you might want to consider a better hash-function here.
        return (I + J + K).GetHashCode();
    }

    public override bool Equals(object obj)
    {
        return base.Equals(obj as MyObject);
    }

    public bool Equals(MyObject other)
    {
        return other != null && other.I == I && other.J == J && other.K == K;
    }
}
公共类MyObject:IEquatable
{
公共字符串I{get;set;}
公共字符串J{get;set;}
公共字符串K{get;set;}
公共覆盖int GetHashCode()
{
你可能想考虑一个更好的哈希函数。
return(I+J+K).GetHashCode();
}
公共覆盖布尔等于(对象对象对象)
{
返回base.Equals(对象作为MyObject);
}
公共布尔等于(MyObject其他)
{
返回other!=null&&other.I==I&&other.J==J&&other.K==K;
}
}

还要记住,密钥对象的哈希值只要存在于字典中就不能改变

在.NET中,
GetHashCode
Equals
方法配合使用,以确定集合中存储的对象相等性

请注意,哈希表比简单地通过哈希代码将密钥映射到单个插槽更复杂。由于散列码的性质,冲突可能会发生,并且在实践中确实会发生(尽管使用好的散列函数,这种情况不应该经常发生)。因此,大多数哈希表实现必须处理两个不同对象生成相同哈希代码的情况,这通常通过哈希表中每个“槽”处的链接列表来实现。哈希代码用于确定插槽,
Equals
方法用于确定对象存储在链表中的位置(在哈希表的大多数“标准”实现中)


然而,有一句话要警告:很少有好的理由重写
GetHashCode
的内置行为。我发现这很有趣,所以讨论
GetHashCode
等于
的线程应该值得一读:。它讨论了改变行为的优点/缺点、好的和坏的哈希函数的属性、这两种方法所需的属性以及其他优点。

+1如果哈希码相等,则调用
等于
方法。hashcodes实际上只是预过滤器,因为比较比
Equals
快得多。由于字典和哈希表为给定的键返回一个且只有一个值,并且如果某个键已经存在,则会引发异常,因此它不会在哈希表的每个插槽中都有链表。