views:

114

answers:

4

I have a list:

private readonly IList<IList<GameObjectController>> removeTargets;
private readonly IList<IList<GameObjectController>> addTargets;

PickUp inherits from GameObjectController. But when I try this:

public IList<PickUp> Inventory

// ... 

gameObjectManager.MoveFromListToWorld(this, user.Model.Inventory);

// ...

    // This queues everything up to be removed, until ProcessMoves...() is called
    public void MoveFromWorldToList(GameObjectController removedFromWorld, IList<GameObjectController> addTarget)
    {
        toBeRemoved.Add(removedFromWorld);
        addTargets.Add(addTarget);
    }

// ...

    /// <summary>
    /// Removes all the GameObjects on which removal is requested from the world.
    /// </summary>
    public void ProcessMovesFromListToWorld()
    {
        for (int i = 0; i < toBeAdded.Count; i++)
        {
            GameObjectController moved = toBeAdded[i];
            addGameObjectToWorld(moved);

            if (removeTargets[i] != null)
            {
                removeTargets[i].Remove(moved);
            }
        }
        toBeAdded.Clear();
        removeTargets.Clear();
    }

I get a compiler error:

cannot convert from 'System.Collections.Generic.IList<PickUp>' to 'System.Collections.Generic.IList<GameObjectController>'

Why does this occur? Shouldn't this be fine, since PickUp is a subclass of GameObjectController? Do I need something like Java's Map<E extends GameObjectController>?

Earlier, I was having a similar problem, where I was trying to implicitly cast inventory from an IList to an ICollection. Is this the same problem?

+6  A: 

See my other answer here:
http://stackoverflow.com/questions/2586705/how-to-return-an-iqueryablesomething-as-an-iqueryableisomething/2586805#2586805

Short version:

Remember that IList<PickUp> and IList<GameObjectController> are two (and only two) completely different classes in the type system. The only inheritance relationship they have comes from the System.Collections branch of the inheritance tree; there is none at all on the GameObjectController branch of the inheritance tree. You might as well try to cast an IList<double> to an IList<ArgumentNullException>.

What you can do instead is call the Cast<T>() extension method that is available for IEnumerable<T>.

Joel Coehoorn
+1  A: 

This is called co- and contravariance and is first supported in c# 4.0. And even then it only works with IEnumerable and not IList.

Danvil
covariance is the name of one possible solution (which won't work here), not the name of the problem.
Joel Coehoorn
Its the heart of the problem.
Danvil
@Danvil - no, it's not. Covariance means a type is allowed to vary (note the root word) in a certain way. _Invariance_ -- or the inability for a type to vary -- is the heart of the problem.
Joel Coehoorn
Well this is a bit philosophic ... You can either see "what he cannot do" (covariance) or "what is preventing him to do so" (invariance) as the heart of the problem.
Danvil
+2  A: 

You can't convert List<BaseClass> to List<DerivedClass>. Here is a recent question that deals with this issue.

Daniel Plaisted
Well, you can convert it if you write code to do so - you just can't cast it.
Joel Mueller
+1  A: 

A list of base objects can certainly hold items of derived objects. What I cannot gather from your code, however, is exactly what you're doing. You have an IList<IList<class>>, and then the implementation of your method is not visible to us. But code like the following certainly works (Bar extends Foo)

IList<Foo> foos = new List<Foo>();
IList<Bar> bars = new List<Bar>() { new Bar(), new Bar() };
foreach (Bar bar in bars)
    foos.Add(bar);

Maybe you're trying to the below scenario? This is where you have a list of lists of base ofjects and a list of lists of derived objects? If so, you can cast like below.

IList<IList<Foo>> listOfFoos = new List<IList<Foo>>() { foos };
IList<IList<Bar>> listOfBars = new List<IList<Bar>>() { bars };

foreach (IList<Bar> b in listOfBars)
{
    listOfFoos.Add(b.Cast<Foo>().ToList());
}
Anthony Pegram
That is correct. I am trying to do the above. How do I want to be doing this?
Rosarch