我已将我的代码简化为以下重现错误的简短示例。我正在尝试将派生类的值绑定到控件。派生类和绑定逻辑是:
bindingSource = new BindingSource();
numericUpDown1.DataBindings.Add("Value", bindingSource, nameof(SinglePoint.Val), false, DataSourceUpdateMode.OnPropertyChanged);
bindingSource.DataSource = new[] { new SinglePoint(100) };
[...]
public class SinglePoint : PointList
{
public SinglePoint(int val) { points.Add(val); }
public int Val
{
get { return points[0]; }
set
{
if (value > 300) value = 300; //(*)
points[0] = value;
}
}
}
因此,当在NumericUpDown
上设置例如值500时,在离开之后我们应该看到300因为行(*)。如果基类未实现GetHashCode
:
public class PointList
{
protected List<int> points = new List<int>();
public PointList() { }
// UNCOMMENT this and the binding will stop working properly
//public override int GetHashCode()
//{
// unchecked
// {
// int hashCode = 17;
// foreach (var item in points)
// hashCode += 13 * item.GetHashCode();
// return hashCode;
// }
//}
}
但是,如果您尝试取消注释GetHashCode
实施,则绑定将中断。这意味着在设置500并离开NumericUpDown
之后,控件仍将显示500,但实际上基础值将为300.为什么会发生这种情况,如何在不关闭{{{{{ 1}}?
修改
正如你们中的一些人所指出的,GetHashCode不应该改变,因为它被绑定机制使用。这回复了我的问题的第一部分。但是,如何使我的PointList类满足其他rule“如果两个相等(Equals(...)== true)那么它们必须为GetHashCode()返回相同的值”。如果我有两个具有相同列表(序列)点的GetHashCode
个对象,我希望它们相等(因为我的代码中的其他逻辑),这应该意味着具有相同的哈希码。你会怎么做?
答案 0 :(得分:3)
Thumb规则:
GetHashCode
返回的整数必须永远不会更改,而对象包含在依赖于哈希代码保持稳定的数据结构中
见Eric Lippert的文章here。
在GetHashCode
中,您应该只使用只读或不可变字段;否则,该对象不能用于Dictionary
,Hashtable
和其他基于散列的集合。
答案 1 :(得分:3)
WinForms使用数据对象和数据成员的哈希码生成密钥,该密钥用于跟踪内部存储中的数据绑定对象。如果更改哈希计算以便在数据成员更改值时哈希更改,则先前生成的密钥不会随之更新,因此与当前密钥不同。这打破了数据绑定机制。
答案 2 :(得分:0)
您应该使用base.GetHashCode()初始化哈希码,而不是将哈希码初始化为17。 int hashCode = base.GetHashCode(); //不是17