majeric
majeric

Reputation: 3

How do you manage a C# Generics class where the type is a container of a base class?

I get the following error

The best overloaded method match for `System.Collections.Generic.List>.Add(MyContainer)' has some invalid arguments (CS1502) (GenericsTest)

For the following class:

A and B are child classes of MyBase.

public class GenericConstraintsTest
{

    private MyList<MyContainer<MyBase>> myList = new MyList<MyContainer<MyBase>>();

    public GenericConstraintsTest ()
    {
        MyContainer<A> ca = new MyContainer<A>(new A());

        this.Add<A>(new A());
        this.Add<B>(new B());
    }


    public void Add<S> (S value) where S : MyBase
    {
        MyContainer<S> cs = new MyContainer<S>(value);
        myList.Add(cs);    
    }


    public static void Main()
    {
        GenericConstraintsTest gct = new GenericConstraintsTest();
    }
}

What am I doing wrong?

Cheers

Upvotes: 0

Views: 204

Answers (1)

Sven
Sven

Reputation: 22683

You are trying to call myList.Add with a MyContainer<A> and a MyContainer<B> respectively. Neither is convertible to MyContainer<MyBase> because two generic instantiations with different generic type parameters are always unrelated, even if the type parameters are related.

The only way to do this is to make an IMyContainer<out T> covariant generic interface. This will allow you to cast IMyContainer<A> to IMyContainer<MyBase> if A derives from MyBase. (Note: only interfaces can have covariant and contravariant type parameters, and this is only available in .Net 4).

For example:

public interface IMyContainer<out T> { }
public class MyContainer<T> : IMyContainer<T> 
{
    public MyContainer(T value) { }
}
public class MyBase { }
public class A : MyBase { }
public class B : MyBase { }

public class GenericConstraintsTest
{

    private List<IMyContainer<MyBase>> myList = new List<IMyContainer<MyBase>>();

    public GenericConstraintsTest()
    {
        MyContainer<A> ca = new MyContainer<A>(new A());

        this.Add<A>(new A());
        this.Add<B>(new B());
    }


    public void Add<S>(S value) where S : MyBase
    {
        MyContainer<S> cs = new MyContainer<S>(value);
        myList.Add(cs);
    }


    public static void Main()
    {
        GenericConstraintsTest gct = new GenericConstraintsTest();
    }
}

Upvotes: 6

Related Questions