2

If I have this code:

public interface IThing<T> where T : class
{
    // ...
}

public class BaseThing<T> : IThing<T> where T : class
{
    // ...
}

public class ThingA : BaseThing<string>
{
    // ...
}

public class ThingB : BaseThing<Uri>
{
    // ...
}

This code fails:

List<IThing<object>> thingList = new List<IThing<object>>();

thingList.Add(new ThingA());
thingList.Add(new ThingB());

Even though ThingA (indirectly) inherits from (and should be an instance of) IThing<T>. Why? Is ThingA/ThingB not an instance of IThing<T>?

qJake
  • 16,821
  • 17
  • 83
  • 135
  • 2
    Read up on covariance and contravariance. (I don't know enough to answer the question other than knowing that these concepts are related.) – zimdanen Sep 27 '13 at 18:19
  • 2
    Note that all "instances" of `IThing` like `IThing`, `IThing`, `IThing` are siblings - there is no inheritance relation between them. There is also no inheritance relation with `IThing` which is really totally different thing (and also different from `IThing<>` - [open generic](http://stackoverflow.com/questions/2173107/what-exactly-is-an-open-generic-type-in-net)). – Alexei Levenkov Sep 27 '13 at 18:36

1 Answers1

7

This would require your interface to be covariant. For details, see Covariance and Contravariance in Generics.

In this case, you can make this work by using:

// Add out here
public interface IThing<out T> where T : class
{
}

Note that this does place limitations on the interface and what you can do with it, however, as it requires that the type T in the interface be used only as a method return type within the interface, and not used as a type of formal method parameters.

If this is not viable, another option is to create a non-generic IThing interface, and have IThing<T> implement IThing. You could then use List<IThing> for your collection.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Yeah, I have properties defined in the interface that use `T` (like `List`), so this won't work. Is there anything else I can change about the design that will make this work, or should I look at re-architecting this? – qJake Sep 27 '13 at 18:27
  • 3
    @SpikeX You'd need to rearchitect it a bit. One option is to make a non-generic `IThing` interface, and have `IThing` implement it. You could then create a `List` and use that... – Reed Copsey Sep 27 '13 at 18:28
  • Creating the non-generic interface to complement the generic one did the trick. The code compiles, and even better, MEF is working again, too. Thanks! – qJake Sep 27 '13 at 18:57