Question

I'm working in C#. I want to remove a Catalog (an object type i've defined earlier) from an ObservableCollection<Catalog>.

I know that when you call Remove,Contains or Add... the VM calls Equals to "locate" the object you want to add or remove. So here are my Catalog.Equals definitions :

public override bool Equals(object obj) 
{
    Catalog cat = (Catalog)obj;
    return (this.Name.Equals(cat.Name));           
}

public bool Equals(Catalog cat)
{
    return (this.Name.Equals(cat.Name));
}

But when I execute myCollection.Remove(catlg) (catlg is of type Catalog), I get an InvalidCastException on the following line : Catalog cat = (Catalog)obj.

Why an invalid cast here ? And why Equals(Catalog cat) isn't called here, instead of Equals(object obj) definition ?

Of course, Remove doesn't work, even if Console.WriteLine(myCollection.Contains(catlg)) is true.

Was it helpful?

Solution

Try implementing the IEquatable<Catalog>.

And get rid of the override perhaps?

OTHER TIPS

One Solution could be to use the linq extension methods.

var catalogToRemove = Catalogs.Single(p => p.Name == catalogName);
Catalogs.Remove(catalogToRemove);

An other could be to implement IEquatable

public class Catalog : IEquatable<Catalog>
{
    public string Name { get; set; }

    public bool Equals(Catalog other)
    {
        return Name == other.Name;
    }
}

The second sulotion is good if you do not have the exact object you want to remove. For example you could create a new Catalog object, set the name to the object you want to remove and use that new object in the Remove method of the collection. If you do not implement IEquatable this will not work since the new object is not exactly the same object that is contained in your collection.

Since you didn't implement IEquatable, the default for the Remove method is to use the Object.Equals method, and not your generic Equals(Catalog);

This is what the documentation states for IList.Remove:

If type T implements the IEquatable generic interface, the equality comparer is the Equals method of that interface; otherwise, the default equality comparer is Object.Equals.

This is what the MSDN documentation states about the IEquatable<T>.Equals:

If you implement Equals, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable.Equals method. If you do override Object.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. In addition, you should overload the

There might be a compare somewhere in your code, where Equals(object) is called with another type that is not a Catalog, via the Equals(System.Object, System.Object), which causes the InvalidOperationException.

Use the as keyword instead of an explicit cast, and make sure you implement IEquatable<Catalog>:

public override bool Equals(object obj) 
{
    Catalog cat = obj as Catalog;
    if (cat == null)
    {
       return;
    }
    return (this.Name.Equals(cat.Name));           
}

You must implement GetHashCode (link)

public override bool Equals(object obj) 
{
    Catalog cat =  obj as Catalog;
    if (cat == null)
    {
        return false;
    }

    return (this.Name.Equals(cat.Name));           
}

I'm using a different cast than you. With the as, you can check if it'is correct.

public bool Equals(Catalog cat)
{
    return (this.Name.Equals(cat.Name));
}

public int GetHashCode(object obj)
{
    // implement your hash code logic here
    return obj.ToString().GetHashCode();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top