1

I'm using List.Contains to tell whether a variable is inside the list or not, but it keeps on returning that it isn't when it is.

I've looked up MSDN and I've noticed that I have to inherit from IEquatable and implement my own .Equals method. The actual class is inheriting from another one, so I've written the .Equals method in the base class.

Here's the code of the class "Actividad":

abstract public class Actividad:IEquatable<Actividad> {

    protected int codigo;

    [...]

    public bool  Equals(Actividad otra)
    {
        return this.Codigo == otra.Codigo;
    }   
}

and here's the definition of the child class "Actividad_a":

public class Actividad_a : Actividad{ [...] }

This is the code that checks whether something is inside the list:

private void loadDisponibles() {

    foreach (Actividad_a act in Program.Asignaturas) {

        if (!user1.ActAcademicas.Contains(act)) {
           doSomething();
        }
    }
}

Program.Asignaturas and user1.ActAcademicas are both defined as List<Actividad_a>.

The problem is that !user1.ActAcademicas.Contains(act) always returns true, no matter the data is in the list or not.

My first guess is that I have to inherit from IEquatable and implement .Equals method in each derived class, but I'm not really sure about it.

vguzmanp
  • 785
  • 1
  • 10
  • 31

1 Answers1

3

You're comparing Actividad_a and the Contains method is expecting it to implement IEquatable<Actividad_a> rather than IEquatable<Actividad>

Try overriding the default Equals method as well

public override bool Equals(object otra)
{
    var actividad = otra as Actividad;
    if (actividad == null) return false;
    return this.Codigo == actividad.Codigo;
}   

EDIT:

Some more info: .NET 4.0 introduced flexibility for working with generics called Contravariance and Covariance http://msdn.microsoft.com/en-us/library/dd799517.aspx

Covariant and contravariant generic type parameters provide greater flexibility in assigning and using generic types. For example, covariant type parameters enable you to make assignments that look much like ordinary polymorphism. Suppose you have a base class and a derived class, named Base and Derived. Polymorphism enables you to assign an instance of Derived to a variable of type Base. Similarly, because the type parameter of the IEnumerable(Of T) interface is covariant, you can assign an instance of IEnumerable (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable

In general, a covariant type parameter can be used as the return type of a delegate, and contravariant type parameters can be used as parameter types. For an interface, covariant type parameters can be used as the return types of the interface's methods, and contravariant type parameters can be used as the parameter types of the interface's methods.

For some reason IEquatable<T> was not made contravariant and why your original approach won't work

Community
  • 1
  • 1
Vadim
  • 17,897
  • 4
  • 38
  • 62
  • 1
    Or, as OP suspects, he could implement IEquatable on every type derived from Actividad. Overriding `object.Equals` in `Actividad` is the better approach, however, so +1. (Also, you need the override keyword in your example code.) – phoog Apr 16 '12 at 22:21
  • This worked smoothly :). I also had to inherit from IEquatable – vguzmanp Apr 16 '12 at 22:27
  • @Fawques, you shouldn't actually have to inherit from IEquatable as all objects have an Equals method as it is. – Vadim Apr 18 '12 at 14:18
  • I just did a override on Equals for my object and it worked like a charm. Thanks! – pStan Jun 24 '13 at 18:42