views:

76

answers:

3

Pretty self explanatory question, glad for any answer. For me it doesn't make sense. I don't care about losing information. I just want to concatenate all my lists that inherit IRenderable somehow into a single list and then call IRenderable methods on it. I have a feeling that this is some basic rule of programming I forgot...

edit: This is the code:

interface IRenderable
{
    void Render();
}
interface IScreen : IRenderable
{
}
public List<IScreen> Screens = new List<IScreen>();
List<IRenderable> renderList = new List<IRenderable>();
renderList = ((List<IRenderable>)Screens; // error: cannot convert type IScreen to IRenderable

edit2: btw, I have .net 4.0 installed, but the reference still stays System.dll Version 2.0.5.0

+2  A: 

My guess is you're really trying to convert from List<IScreen> to List<IRenderable> or something similar.

You can't do this at all prior to .NET 4 due to generic invariance. In .NET 4, you can do it for interfaces and delegates where appropriate. In particular, you can convert from IEnumerable<IScreen> to IEnumerable<IRenderable>. If you're just trying to concatenate a list, that should be okay - you should be able to use List<T>.AddRange with each of your lists... but again, this only applies in C# 4. Another option in C# 4 would be something like:

var combined = firstList.Concat<IRenderable>(secondList).ToList();

As an example of why this isn't always safe (the permitted uses in C# 4 are safe) consider this code:

List<Apple> apples = new List<Apple> { new Apple(...) };
List<Fruit> fruit = apples;
fruit.Add(new Orange());

Now the list that apples refers to contains an orange! This clearly isn't a good thing from a type safety perspective.

As driis says, if you can give more details (e.g. what you've got and what you want) we should be able to help more.

Jon Skeet
+1  A: 

You don't give a lot of details. But let's assume you have:

IRenderable {}

IScreen : IRenderable {}

private List<IRenderable> ConcatLists(IEnumerable<IRenderable> first, IEnumerable<IRenderable> second) { ... }

Now, you will not be able to call the ConcatLists method directly with an IEnumerable<IScreen>, in C# versions prior to C#4. The reason for this is called co- and contravariance. In Framework 4, IEnumerable<T> is declared covariant, which means that it can be implicitly converted to a IEnumerable where T is of a lesser type (IRenderable in your case).

If you want to call such a method in C#3, you can use an extension method to help you.

This might be:

ConcatLists(first.Cast<IRenderable>(), second);

If "first" is declared to be of type IRenderable.

driis
+1  A: 

List<T0> is not castable to List<T1>. You should do casting for every element of list. The Cast extension for IEnumarable is do this:

List<IScreen> Screens = new List<IScreen>();
List<IRenderable> renderList = Screens.Cast<IRenderable>().ToList();
Sessiz Saat
Isn't this very bad for performance?
Blub
no. it just do casting. But ToList method have some cost (neglible) because of reallocation. I commend IEnumerable<T> instead list<T> if you dont have any reason required
Sessiz Saat
what kind of reallocation? my app is performance critical
Blub
I mean that when ToList method called, a new list constructed with the items at new place im memory. What kind of app is yours? emdedded? do you have resource limitation?
Sessiz Saat