简体   繁体   English

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

[英]why don't List<T>.GetHashCode and ObservableCollection<T>.GetHashCode evaluate their items?

I think it is strange that the GetHashCode function of these collections don't base their hashcode on the items in their lists. 我认为奇怪的是,这些集合的GetHashCode函数没有将其哈希码基于其列表中的项目。

I need this to work in order to provide dirty checking (you have unsaved data). 我需要它来提供脏检查(您有未保存的数据)。 I've written a wrapping class that overrides the GetHashCode method but I find it weird that this is not the default implementation. 我编写了一个包装类,该包装类重写了GetHashCode方法,但我发现这不是默认的实现,这很奇怪。

I guess this is a performance optimization? 我猜这是性能优化吗?

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

If it did, it would break a few of the guidelines for implementing GetHashCode . 如果这样做的话,将破坏一些实现GetHashCode准则 Namely: 即:

the integer returned by GetHashCode should never change GetHashCode返回的整数不应更改

Since the content of a list can change, then so would its hash code. 由于列表的内容可以更改,因此其哈希码也可以更改。

the implementation of GetHashCode must be extremely fast GetHashCode的实现必须非常快

Depending on the size of the list, you could risk slowing down the calculation of its hash code. 根据列表的大小,您可能会冒险减慢其哈希码的计算。

Also, I do not believe you should be using an object's hashcode to check if data is dirty. 另外,我不认为您应该使用对象的哈希码来检查数据是否脏了。 The probability of collision is higher than you think . 发生碰撞的可能性比您想象的要高

The Equals/GetHashCode of lists checks for reference equality, not content equality. 列表的Equals / GetHashCode检查引用相等性,而不是内容相等性。 The reason behind this is, that lists are both mutable and by reference (not struct) objects. 这背后的原因是,列表都是可变的,并且是引用对象(而不是结构对象)。 So every time you change the contents, the hash code would change. 因此,每次更改内容时,哈希码都会更改。

The common use case of hash codes are hash tables (for example Dictionary<K,V> or HashSet), which sort their items based on hash when the are first inserted into the table. 哈希码的常见用例是哈希表(例如Dictionary<K,V>或HashSet),这些哈希表在首次插入哈希表时会根据哈希对它们的项进行排序。 If the hash of an object wich is already in the table changes, it may no longer be found, wich leads to erratic behavior. 如果表中已存在对象的哈希值已更改,则可能不再找到该哈希值,这将导致行为不稳定。

The key of GetHashCode is to reflect the Equals() logic, in a light weight way. GetHashCode的关键是以轻量级的方式反映Equals()逻辑。

And List<T>.Equals() inherits Object.Equals() , and Object.Equals() compares the equality by reference, so that the list do not based on it's items, but the list itself List<T>.Equals()继承Object.Equals() ,而Object.Equals()通过引用比较相等性,因此列表不基于其项,而是列表本身

It would be helpful to have a couple types which behaved like List<T> and could generally be used interchangeably with it, but with GetHashCode and Equals methods which would define equivalence either in terms of the sequence of identities, or the Equals and GetHashCode behaviors of the items encapsulated therein. 拥有一些行为类似于List<T>并通常可以与其互换使用的类型将很有帮助,但是使用GetHashCodeEquals方法可以根据标识序列或EqualsGetHashCode行为定义等效性封装在其中的物品。 Making such methods to behave efficiently, however, would require that the class include code to cache its hash value but invalidate or update the cached hash value whenever the collection was modified (it would not be legitimate to modify a list while it was stored as a dictionary key, but it should be legitimate to remove a list, modify it, and re-add it, and it would be very desirable to avoid having such modification necessitate re-hashing the entire contents of the list). 但是,要使此类方法有效地运行,就要求该类包含代码以缓存其哈希值,但是每当修改集合时都将使缓存的哈希值无效或更新(将列表存储为列表时修改列表是不合法的)。字典键,但是删除列表,对其进行修改并重新添加它应该是合法的,并且非常需要避免进行此类修改,从而不必重新散列表的全部内容。 It was not considered worthwhile to have ordinary lists go through the effort of supporting such behavior at the cost of slowing down operations on lists that never get hashed; 普通列表不值得花很多时间来支持这种行为,而这样做会减慢对列表的操作,而这些操作永远不会被散列。 nor was it considered worthwhile to define multiple types of list, multiple types of dictionary, etc. based upon the kind of equivalence they should look for in their members or should expose to the outside world. 也没有必要根据他们应该在其成员中寻找的种类或应该暴露给外界的等同性来定义多种类型的列表,多种类型的词典等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM