覆盖 GetHash 代码和 Equals 中断绑定
Overriding GetHash code and Equals break bindings
目前我遇到了问题,当我覆盖 GetHashCode
和 Equals
时,我的绑定被破坏了。
这是我的模型:
class A
{
private string name;
public string Name
{
get { return name; }
set { name = value; /*Some notification stuff*/ }
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
else if (obj is A)
{
return (obj as A).Name == this.name;
}
else
{
return false;
}
}
public override int GetHashCode()
{
if (name != null)
{
return name.GetHashCode();
}
else
{
return 0;
}
}
}
class B
{
private ObservableCollection<A> items;
private A selectedItem;
public ObservableCollection<A> Items
{
get { return items; }
set { items = value; /*Some notification stuff*/ }
}
public A SelectedItem
{
get { return selectedItem; }
set { selectedItem = value; /*Some notification stuff*/ }
}
}
xaml如下:
<Label Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Content="A:" />
<TextBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="24"
Text="{Binding SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diagnostics:PresentationTraceSources.TraceLevel=High}" />
<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Content="List" />
<ListBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding Items, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diagnostics:PresentationTraceSources.TraceLevel=High,
ValidatesOnDataErrors=True}" DisplayMemberPath="Name" />
问题是,如果我覆盖 GetHashCode
和 Equals
绑定仅在第一次选择项目并更改名称时起作用。在那之后它似乎坏了。我添加了一些绑定调试,但是 returns 没有错误或 detaching/deactivation.
如果我删除覆盖,每个想法都可以正常工作。
我是不是做错了什么?
覆盖 Equals
在你的情况下看起来没问题,它应该不会破坏任何东西。
但是以这种方式覆盖 GetHashCode
(即在计算哈希码时使用 属性 和 public setter)会中断 class 的检索A
使用散列码的集合中的项目(例如,来自 Dictionary
)如果您要在添加到集合后更改此 属性 值。
您还可以从 Eric Lippert 的有关 GetHashCode 指南和规则的博客中找到有趣的 this article。
您的解决方案是接受table。
考虑将 A
设为 sealed class
或检查是否 this.GetType() == obj.GetType()
(当然,在 obj
不为 null 的情况下)。如果 this
比 obj
更派生,或者如果 obj
比 this
更派生,你应该 return false。
在覆盖 Equals
.
后,永远不要保留 GetHashCode
的基本 class 行为
正如 Andy Korneyev 在他的回答中所说,请注意 Equals
(因此也是 GetHashCode
)的 mutable 对象在实例添加到 Hashtable
、Dictionary<,>
、HashSet<>
等可能很危险。如果对象在哈希 table 持有对它的引用时发生变化,则该哈希 table 将被搞砸,并且该对象可能无法在该哈希 [= 中的 O(1) 查找中找到37=].
目前我遇到了问题,当我覆盖 GetHashCode
和 Equals
时,我的绑定被破坏了。
这是我的模型:
class A
{
private string name;
public string Name
{
get { return name; }
set { name = value; /*Some notification stuff*/ }
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
else if (obj is A)
{
return (obj as A).Name == this.name;
}
else
{
return false;
}
}
public override int GetHashCode()
{
if (name != null)
{
return name.GetHashCode();
}
else
{
return 0;
}
}
}
class B
{
private ObservableCollection<A> items;
private A selectedItem;
public ObservableCollection<A> Items
{
get { return items; }
set { items = value; /*Some notification stuff*/ }
}
public A SelectedItem
{
get { return selectedItem; }
set { selectedItem = value; /*Some notification stuff*/ }
}
}
xaml如下:
<Label Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Content="A:" />
<TextBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="24"
Text="{Binding SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diagnostics:PresentationTraceSources.TraceLevel=High}" />
<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Content="List" />
<ListBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding Items, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, diagnostics:PresentationTraceSources.TraceLevel=High,
ValidatesOnDataErrors=True}" DisplayMemberPath="Name" />
问题是,如果我覆盖 GetHashCode
和 Equals
绑定仅在第一次选择项目并更改名称时起作用。在那之后它似乎坏了。我添加了一些绑定调试,但是 returns 没有错误或 detaching/deactivation.
如果我删除覆盖,每个想法都可以正常工作。
我是不是做错了什么?
覆盖 Equals
在你的情况下看起来没问题,它应该不会破坏任何东西。
但是以这种方式覆盖 GetHashCode
(即在计算哈希码时使用 属性 和 public setter)会中断 class 的检索A
使用散列码的集合中的项目(例如,来自 Dictionary
)如果您要在添加到集合后更改此 属性 值。
您还可以从 Eric Lippert 的有关 GetHashCode 指南和规则的博客中找到有趣的 this article。
您的解决方案是接受table。
考虑将 A
设为 sealed class
或检查是否 this.GetType() == obj.GetType()
(当然,在 obj
不为 null 的情况下)。如果 this
比 obj
更派生,或者如果 obj
比 this
更派生,你应该 return false。
在覆盖 Equals
.
GetHashCode
的基本 class 行为
正如 Andy Korneyev 在他的回答中所说,请注意 Equals
(因此也是 GetHashCode
)的 mutable 对象在实例添加到 Hashtable
、Dictionary<,>
、HashSet<>
等可能很危险。如果对象在哈希 table 持有对它的引用时发生变化,则该哈希 table 将被搞砸,并且该对象可能无法在该哈希 [= 中的 O(1) 查找中找到37=].