1

Say I have a setup like

public interface IMyInterface { }

public class MyImplementation : IMyInterface { }

public class MyClass<T> where T : IMyInterface { }

I figured out that I can't do a substitution like

var list = new List<MyClass<IMyInterface>>()
{
   new MyClass<MyImplementation>()
}

as I'll get the error

Cannot convert from MyClass<MyImplementation> to MyClass<IMyInterface>

Does that mean what I'm trying to do is code smell?

Hiram Katz
  • 383
  • 1
  • 2
  • 7
  • Its a compiler error so it means what you are trying to do is illegal in the c# language. – Dave May 16 '18 at 21:35
  • You cannot do that because `T` in `List` is invariant. In other words, it has to be of one type (it cannot vary). Google covariance and contravariance. Also this question has been asked one too many times on SO. – CodingYoshi May 16 '18 at 21:37
  • I think what you want to look into is Variance with Generics in C#, the two key terms are Co-Variance and Contra-Variance. I'm not going to give an answer as it probably won't cover it well, as it's something that still gives me a headache, so my advice is to look up those terms until someone more knowledgeable can give you a good answer – Dave May 16 '18 at 21:37
  • Possible duplicate of [Generic Variance in C# 4.0](https://stackoverflow.com/questions/2208043/generic-variance-in-c-sharp-4-0) – Dave May 16 '18 at 21:39

1 Answers1

0

It does not allow that because the T in List<T> is invariant. Here is an example which will explain:

public interface IFruit
{
    string Name { get; set; }
}

public class Apple : IFruit
{
    public string Name { get; set; }
    public string Color { get; set; }
}

public class Orange : IFruit
{
    public string Name { get; set; }
}

Let's add some fruits to a list:

var fruits = new List<IFruit>();
fruits.Add(new Apple());
fruits.Add(new Orange());

Later in the code, you have no idea what was added and you do this:

Orange orange = fruits[0];

Now that will not compile but it also does not make sense because every IFruit is not an Apple or an Orange.

What if the compiler allowed it?

If, for instance let's say, what you are trying was allowed by the compiler, like this:

// does not compile but let's say it did
List<Apple> fruits = new List<IFruit>(); 

Then if the compiler allowed that, it should also allow this since they both implement IFruit:

fruits.Add(new Apple());
fruits.Add(new Orange());

then later on somewhere in code you do this (since it is a list of apples):

foreach (var thisFruit in fruits)
{
    Console.WriteLine(thisFruit.Color)
}

Crash!! The compiler did not stop you at the beginning and at this point you are looking at the code and it says List<Apple>, and you wrote code and all compiled. At runtime, oh crap, there is no Color property because it is an Orange.

This is why it is not allowed.

CodingYoshi
  • 25,467
  • 4
  • 62
  • 64