2

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?

BendEg
  • 20,098
  • 17
  • 57
  • 131

2 Answers2

2

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

But overriding of GetHashCode in such a manner (i.e. 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.

Andrey Korneyev
  • 26,353
  • 15
  • 70
  • 71
  • I searched some more, and this seems to be the problem: `will break retrieving of class A item from collections using hash code`. Thank you very much. – BendEg Sep 29 '15 at 07:08
  • 1
    **You must** override `GetHashCode` to ensure that different instances that are `Equals` (because their `Name` are the same) at least produce the same hash. **Keeping the base class behavior** of `GetHashCode` will break everything! The very least you can do as `public override int GetHashCode() { return 0; }` but the asker's solution is a bit better. – Jeppe Stig Nielsen Sep 29 '15 at 07:26
  • @JeppeStigNielsen yes, you're right. Missed that point, probably need more coffee at the morning before answering. ;) Removed confusing part of answer. – Andrey Korneyev Sep 29 '15 at 07:31
1

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.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181