覆盖 GetHash 代码和 Equals 中断绑定

Overriding GetHash code and Equals break bindings

目前我遇到了问题,当我覆盖 GetHashCodeEquals 时,我的绑定被破坏了。

这是我的模型:

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" />

问题是,如果我覆盖 GetHashCodeEquals 绑定仅在第一次选择项目并更改名称时起作用。在那之后它似乎坏了。我添加了一些绑定调试,但是 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 的情况下)。如果 thisobj 更派生,或者如果 objthis 更派生,你应该 return false。

在覆盖 Equals.

后,永远不要保留 GetHashCode 的基本 class 行为

正如 Andy Korneyev 在他的回答中所说,请注意 Equals(因此也是 GetHashCode)的 mutable 对象在实例添加到 HashtableDictionary<,>HashSet<> 等可能很危险。如果对象在哈希 table 持有对它的引用时发生变化,则该哈希 table 将被搞砸,并且该对象可能无法在该哈希 [= 中的 O(1) 查找中找到37=].