C# 为什么不';t列表<;T>;。GetHashCode和ObservableCollection<;T>;。GetHashCode评估他们的项目?
我认为奇怪的是,这些集合的GetHashCode函数没有将它们的hashcode基于列表中的项目 我需要这项工作,以提供脏检查(您有未保存的数据)。 我已经编写了一个覆盖GetHashCode方法的包装类,但我发现这不是默认实现,这很奇怪 我想这是一个性能优化C# 为什么不';t列表<;T>;。GetHashCode和ObservableCollection<;T>;。GetHashCode评估他们的项目?,c#,hashcode,C#,Hashcode,我认为奇怪的是,这些集合的GetHashCode函数没有将它们的hashcode基于列表中的项目 我需要这项工作,以提供脏检查(您有未保存的数据)。 我已经编写了一个覆盖GetHashCode方法的包装类,但我发现这不是默认实现,这很奇怪 我想这是一个性能优化 class Program { static void Main(string[] args) { var x = new ObservableCollection<test>();
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;
}
}
类程序
{
静态void Main(字符串[]参数)
{
var x=新的ObservableCollection();
int hash=x.GetHashCode();
x、 添加(新测试(“名称”);
int hash2=x.GetHashCode();
var z=新列表();
int hash3=z.GetHashCode();
z、 增加(新试验(“tets”);
int hash4=z.GetHashCode();
var my=新的CustomObservableCollection();
int hash5=my.GetHashCode();
var测试=新测试(“名称”);
添加(测试);
int hash6=my.GetHashCode();
test.Name=“name2”;
int hash7=my.GetHashCode();
}
}
公开课考试
{
公共测试(字符串名称)
{
名称=名称;
}
公共字符串名称{get;set;}
公共覆盖布尔等于(对象对象对象)
{
如果(obj是测试)
{
var o=(测试)obj;
返回o.Name==this.Name;
}
返回基数等于(obj);
}
公共覆盖int GetHashCode()
{
返回Name.GetHashCode();
}
}
公共类CustomObservableCollection:ObservableCollection
{
公共覆盖int GetHashCode()
{
int collectionHash=base.GetHashCode();
foreach(项目中的var项目)
{
var itemHash=item.GetHashCode();
if(int.MaxValue-itemHash>collectionHash)
{
collectionHash=collectionHash*-1;
}
collectionHash+=itemHash;
}
返回集合哈希;
}
}
GetHashCode的关键是以轻量级的方式反映Equals()
逻辑
和
List.Equals()
继承Object.Equals()
,而Object.Equals()
通过引用比较相等,这样列表就不基于它的项,而是列表本身GetHashCode
的关键是以轻量级的方式反映Equals()
逻辑
和
List.Equals()
继承Object.Equals()
,和Object.Equals()
通过引用比较相等性,因此列表不基于其项目,而是列表本身列表的Equals/GetHashCode检查引用相等性,而不是内容相等性。这背后的原因是,列表既是可变的对象,也是按引用(而不是结构)的对象。因此,每次更改内容时,哈希代码都会更改
哈希代码的常见用例是哈希表(例如
Dictionary
或HashSet),当第一次将哈希插入表中时,哈希表根据哈希对其项进行排序。如果表中已存在的对象的哈希值发生更改,则可能无法再找到该对象,从而导致行为不稳定。列表的Equals/GetHashCode检查引用相等,而不是内容相等。这背后的原因是,列表既是可变的对象,也是按引用(而不是结构)的对象。因此,每次更改内容时,哈希代码都会更改
哈希代码的常见用例是哈希表(例如
Dictionary
或HashSet),当第一次将哈希插入表中时,哈希表根据哈希对其项进行排序。如果表中已存在的对象的哈希值发生更改,则可能无法再找到该对象,从而导致行为不稳定。如果更改了,则会破坏一些属性。即:
GetHashCode返回的整数永远不会更改
由于列表的内容可以更改,因此其哈希代码也可以更改
GetHashCode的实现必须非常快
根据列表的大小,可能会降低其哈希代码的计算速度
另外,我认为您不应该使用对象的哈希代码来检查数据是否脏 如果它这样做了,它会打破一些规则。即: GetHashCode返回的整数永远不会更改 由于列表的内容可以更改,因此其哈希代码也可以更改 GetHashCode的实现必须非常快 根据列表的大小,可能会降低其哈希代码的计算速度
另外,我认为您不应该使用对象的哈希代码来检查数据是否脏 如果有两种类型,它们的行为类似于
List
,通常可以与之互换使用,但是可以与GetHashCode
和Equals
方法一起使用,这些方法可以根据身份序列定义等价性,或者等于和GetHashCode
中封装的项目的行为。然而,要使这些方法高效运行,需要类包含缓存其哈希值的代码,但在修改集合时使缓存的哈希值无效或更新(在列表作为字典键存储时修改列表是不合法的,但删除、修改并重新添加列表应该是合法的,并且非常希望避免这种修改需要重新散列列表的全部内容)。不值得让普通列表通过努力来支持这种行为,而代价是降低对从不散列的列表的操作速度;也不值得根据它们应该在me中寻找的等效类型来定义多种类型的列表、多种类型的字典等mber或应暴露于