简体   繁体   中英

Overriding GetHash code and Equals break bindings

Currently i have the problem, that when i override GetHashCode and Equals , my binding get's broken.

This are my models:

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*/ }
    }
}

The xaml is the following:

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

The problem is, if i override GetHashCode and Equals the binding only working the first time selecting an item and changing the name. After that it seems broken. I've added some binding debugging but this returns no errors or detaching/deactivation.

If i remove the overridings, every think works fine.

Am i doing some thing wrong here?

Overriding of Equals looks ok in your case and it should not break anything.

But overriding of GetHashCode in such a manner (ie using property with public setter in calculation of hashcode) will break retrieving of class A item from collections using hash code (for example, from Dictionary ) if you will change this property value after adding into collection.

Also you may find interesting this article from Eric Lippert's blog concerning guidelines and rules for GetHashCode.

Your solution is acceptable.

Consider either making A a sealed class or checking whether this.GetType() == obj.GetType() (in the case where obj is not null, of course). If this is more derived than obj , or if obj is more derived than this , you should return false.

Never keep the base class behavior of GetHashCode when you have overridden Equals .

As Andy Korneyev said in his answer, be aware that a mutable object where Equals (and hence also GetHashCode ) can change after the instance was added to a Hashtable , Dictionary<,> , HashSet<> etc. can be dangerous. If the object is mutated while a hash table holds a reference to it, that hash table will be screwed up, and the object might be impossible to locate on O(1) lookups in that hash table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM