为什么不列出<t> .GetHashCode和ObservableCollection <t> .GetHashCode评估他们的项目?

时间:2015-05-29 06:53:30

标签: c# hashcode

我认为这些集合的GetHashCode函数不会将其哈希码基于其列表中的项目,这很奇怪。

我需要这个才能提供脏检查(你有未保存的数据)。 我编写了一个覆盖GetHashCode方法的包装类,但我发现这不是默认实现,这很奇怪。

我猜这是性能优化?

class Program
{
    static void Main(string[] args)
    {
        var x = new ObservableCollection<test>();
        int hash = x.GetHashCode();
        x.Add(new test("name"));
        int hash2 = x.GetHashCode();

        var z = new List<test>();
        int hash3 = z.GetHashCode();
        z.Add(new test("tets"));
        int hash4 = z.GetHashCode();

        var my = new CustomObservableCollection<test>();
        int hash5 = my.GetHashCode();
        var test = new test("name");
        my.Add(test);
        int hash6 = my.GetHashCode();
        test.Name = "name2";
        int hash7 = my.GetHashCode();
    }
}

public class test
{
    public test(string name)
    {
        Name = name;
    }

    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        if (obj is test)
        {
            var o = (test) obj;
            return o.Name == this.Name;
        }
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

public class CustomObservableCollection<T> : ObservableCollection<T>
{
    public override int GetHashCode()
    {
        int collectionHash = base.GetHashCode();

        foreach (var item in Items)
        {
            var itemHash = item.GetHashCode();
            if (int.MaxValue - itemHash > collectionHash)
            {
                collectionHash = collectionHash * -1;
            }
            collectionHash += itemHash;
        }
        return collectionHash;
    }
}

4 个答案:

答案 0 :(得分:5)

如果确实如此,它会打破guidelines for implementing GetHashCode中的一些。即:

  

GetHashCode返回的整数永远不会改变

由于列表的内容可以改变,因此其哈希码也会改变。

  

GetHashCode的实现必须非常快

根据列表的大小,您可能会降低其哈希码的计算速度。

另外,我不相信您应该使用对象的哈希码来检查数据是否脏。 The probability of collision is higher than you think

答案 1 :(得分:3)

列表的Equals / GetHashCode检查引用相等性,而不是内容相等性。这背后的原因是,列表是可变和引用(不是struct)对象。因此,每次更改内容时,哈希码都会发生变化。

哈希码的常见用例是哈希表(例如Dictionary<K,V>或HashSet),它们在首次插入表时根据哈希对其项进行排序。如果表中已经存在的对象的哈希值发生变化,则可能无法再找到它,导致行为不稳定。

答案 2 :(得分:0)

GetHashCode的关键是以轻量级的方式反映Equals()逻辑。

List<T>.Equals()继承Object.Equals()Object.Equals()通过引用比较相等,这样列表不会基于它的项目,而是基于列表本身

答案 3 :(得分:0)

如果某些类型的行为类似于List<T>并且通常可与其互换使用,那么将会很有帮助,但使用GetHashCodeEquals方法可以定义等效性身份序列,或封装在其中的项目的EqualsGetHashCode行为。然而,使这些方法有效地运行将要求该类包括用于缓存其哈希值的代码,但是每当修改集合时使无效或更新缓存的哈希值(在将列表存储为列表时修改列表是不合法的。字典密钥,但删除列表,修改它并重新添加它应该是合法的,并且非常希望避免这种修改需要重新散列列表的整个内容)。普通的名单通过支持这种行为的努力被认为是值得的,这种行为的代价是放慢从未得到散列的名单上的操作;也不值得定义多种类型的列表,多种类型的字典等,这取决于他们应该在其成员中寻找的等价类型,或者应该暴露给外部世界。

相关问题