重写GetHash代码和Equals中断绑定

时间:2015-09-29 06:52:46

标签: c# wpf binding equals gethashcode

目前我遇到了问题,当我覆盖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,绑定仅在第一次选择项目并更改名称时才起作用。之后它似乎破碎了。我已经添加了一些绑定调试,但这不会返回任何错误或分离/停用。

如果我删除了覆盖,每个想法都可以。

我在这里做错了吗?

2 个答案:

答案 0 :(得分:2)

覆盖Equals在你的情况下看起来没问题,它不会破坏任何东西。

但是以这种方式覆盖GetHashCode(即在计算哈希码时使用带有公共setter的属性)将破坏使用哈希码从集合中检索类A项(例如,来自{{ 1}})如果你在添加到集合后改变这个属性值。

您也可以从Eric Lippert的博客中找到有关GetHashCode指南和规则的有趣this article

答案 1 :(得分:1)

您的解决方案是可以接受的。

考虑将A设为sealed class或检查this.GetType() == obj.GetType()(当然obj不为空的情况)。如果this的派生程度高于obj,或obj的派生程度高于this,则应返回false。

覆盖GetHashCode时,切勿保持Equals 的基类行为。

正如Andy Korneyev在他的回答中所说,请注意一个可变对象Equals(因此也GetHashCode)可以在将实例添加到Hashtable Dictionary<,>后更改HashSet<> 1}},.procmailrc等可能很危险。如果对象在哈希表保存对它的引用时发生了变异,那么该哈希表将被搞砸,并且该对象可能无法在该哈希表中的O(1)查找中找到。