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