代码之家  ›  专栏  ›  技术社区  ›  Ramesh César Landesa

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

  •  2
  • Ramesh César Landesa  · 技术社区  · 14 年前

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

    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类,它充当dictionary的键,我重写GetHashCode方法,根据类中存储的值返回哈希代码。

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

    为什么会有这样的行为?

    2 回复  |  直到 14 年前
        1
  •  7
  •   Community    7 年前

    在.NET中, GetHashCode Equals

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

    然而,警告一句:很少有好的理由推翻 方法 方法 等于 这应该值得一读: Why is it important to override GetHashCode when Equals method is overridden?

        2
  •  3
  •   Ani    14 年前

    你需要重写 Object.Equals .

    Dictionary<TKey, TValue> 必要的 但是 完全相等的条件,因为可能发生哈希冲突。在您的示例中,key getter会找到要搜索的正确哈希桶,甚至考虑 obj1 Equals 基于引用相等,则被拒绝。

    理想情况下,实施 IEquatable<T>

    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;
        }
    }
    

    还要记住,只要键对象存在于字典中,它的哈希就不能改变。