Reputation: 3979
If I have List<T>
which got some lists from type MyClass
, for example List<List<MyClass>>
and MyClass
is the parent class from MyClassB
. Why I can't do the following?
List<List<MyClass>> allLists = new List<List<MyClass>>();
List<MyClassB> myList = new List<MyClassB>();
myList.Add(new MyClassB());
//And now the point which dont work
allLists.Add(myList);
If I implement a method I can say SomeClass<T> ... where T : MyClass
, is there something similar for my list problem?
So that I can add lists from any child class to my first-level list?
Upvotes: 1
Views: 258
Reputation: 4583
Even though MyClassB is a sub type of MyClass, it doesn't mean that List is a sub type of List. The question you want to ask is why List isn't covariant with T (which would cause List to be a subtype of List where T is a subtype of Y. Look up the terms covariance and contravariance.
The answer is two fold. Firstly List was implemented before C# implemented co- and contravariance. But most importantly, you can only be covariant if T is an "out" type. Since you can shove stuff into a list, it is not an out type. IEnumerable only emits objects of type T. Therefore, it can be covariant.
Upvotes: 0
Reputation: 660463
class Animal {}
class Tiger : Animal {}
class Giraffe : Animal {}
...
List<Giraffe> giraffes = new List<Giraffe>();
List<List<Animal>> lists = new List<List<Animal>>();
lists.Add(giraffes); // Illegal!
Your question is "why is that illegal?" The answer is: suppose it were legal and let's keep going...
List<Animal> animals = lists[0]; // Obviously typesafe.
animals.Add(new Tiger()); // Obviously typesafe
And we just added a tiger to a list of giraffes.
Since the two latter steps are obviously typesafe, the place that cannot be typesafe must be Add(giraffes)
.
Now, as of C# 4, this does work:
List<IEnumerable<Animal>> lists = new List<IEnumerable<Animal>>();
lists.Add(giraffes);
Why is that legal? Because there is no Add
method on IEnumerable<T>
:
IEnumerable<Animal> animals = lists[0];
And now we can't violate type safety because there's no way to put a tiger into that list of giraffes if we only are accessing it via IEnumerable<T>
.
By the way, someone asks this question almost every day. Do a web search for "C# covariance and contravariance" and you'll get a lot more information about it.
Upvotes: 9
Reputation: 348
You need to tell the compiler that MyClass is the parent from MyClassB i think. This article about the where
keyword may help you further
Upvotes: 0
Reputation: 1659
This will fix the issue:
List<MyClass> myList = new List<MyClass>();
Upvotes: 0
Reputation: 655
The problem is that AllLists is strongly-typed to contain lists of MyClass. MyList is strongly-typed to contain instances of MyClassB.
Whereas you'd be able to store List in your List>, there is a type mismatch in your current code.
Upvotes: 0
Reputation: 21495
You have to use as the inner collection an interface that allows derived classes (called covariant interface):
var allLists = new List<IEnumerable<MyClass>>();
Upvotes: 2
Reputation: 726987
The reason that you cannot do it is as follows: imagine that allLists.Add(myList)
worked. Then the compiler would know that allLists[0]
is a List<MyClass>
, so the following would be OK:
allLists[0].Add(new MyClassX());
That would be a runtime error, because allLists[0]
is actually a List<MyClassB>
. It is not capable of holding MyClassX
objects.
If you change your code so that myList
is a List<MyClass>
, your code would work:
List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClassB()); // This works, because MyClassB extends MyClass
allLists.Add(myList); // This works, too
Upvotes: 8
Reputation: 3331
List<List<MyClass>> allLists = new List<List<MyClass>>();
the list you are adding is the not same type. You may do like this:
interface IMyClass
{
//some properties
}
All your child classes must inherit from IMyClass. Then you will have list like this.
List<List<IMyClass>> allLists = new List<List<IMyClass>>();
Upvotes: 0