Я работаю на C #. Я хочу удалить Каталог (тип объекта, который я определил ранее) из ObservableCollection<Catalog>.

Я знаю, что когда вы вызываете Remove, Contains или Add ... виртуальная машина вызывает Equals, чтобы «найти» объект, который вы хотите добавить или удалить. Итак, вот мои определения Catalog.Equals:

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));
}

Но когда я выполняю myCollection.Remove(catlg) (catlg имеет тип Catalog), я получаю InvalidCastException в следующей строке: Catalog cat = (Catalog)obj.

Почему здесь неверный состав? И почему здесь не вызывается Equals (Catalog cat), а не определение Equals (object obj)?

Конечно, Remove не работает, даже если Console.WriteLine(myCollection.Contains(catlg)) истинно.

2
Adrien Budet 28 Апр 2014 в 12:51

4 ответа

Лучший ответ

Попробуйте реализовать IEquatable<Catalog>.

И, возможно, избавиться от override?

1
bit 28 Апр 2014 в 08:58

Одним из решений может быть использование методов расширения linq.

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

Другой может быть реализация IEquatable

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

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

Второй вариант хорош, если у вас нет того объекта, который вы хотите удалить. Например, вы можете создать новый объект каталога, присвоить имя объекту, который хотите удалить, и использовать этот новый объект в методе Remove коллекции. Если вы не реализуете IEquatable, это не сработает, поскольку новый объект - это не совсем тот же объект, который содержится в вашей коллекции.

0
Andre 28 Апр 2014 в 09:09

Поскольку вы не реализовали IEquatable, по умолчанию для метода Remove используется метод Object.Equals, а не ваш общий Equals (Каталог);

Вот что говорится в документации для IList.Remove:

Если тип T реализует универсальный интерфейс IEquatable , равенство comparer - это метод Equals этого интерфейса; в противном случае Компаратором равенства по умолчанию является Object.Equals.

Вот что говорится в документации MSDN о IEquatable<T>.Equals:

Если вы реализуете Equals, вы также должны переопределить базовый класс реализации Object.Equals (Object) и GetHashCode, чтобы их поведение согласуется с поведением метода IEquatable.Equals. Если вы переопределите Object.Equals (Object), ваш переопределенный реализация также вызывается при вызове статического Equals (System.Object, System.Object) в вашем классе. В кроме того, вы должны перегрузить

Где-то в вашем коде может быть сравнение, где Equals (объект) вызывается с другим типом, который не является Catalog, через Equals(System.Object, System.Object), что вызывает InvalidOperationException.

Используйте ключевое слово as вместо явного приведения и убедитесь, что вы реализовали IEquatable<Catalog>:

public override bool Equals(object obj) 
{
    Catalog cat = obj as Catalog;
    if (cat == null)
    {
       return;
    }
    return (this.Name.Equals(cat.Name));           
}
0
Yuval Itzchakov 28 Апр 2014 в 09:13

Вы должны реализовать GetHashCode (ссылка)

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

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

Я использую другой состав, чем ты. С помощью as вы можете проверить его правильность.

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();
}
0
Xaruth 28 Апр 2014 в 09:16