1

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?

kvb
  • 54,864
  • 2
  • 91
  • 133
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699

4 Answers4

6

See my other answer here:
How to return an IQueryable<Something> as an IQueryable<ISomething>

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>.

Community
  • 1
  • 1
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
2

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

Community
  • 1
  • 1
Daniel Plaisted
  • 16,674
  • 4
  • 44
  • 56
1

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
  • 22,240
  • 19
  • 65
  • 88
  • 2
    covariance is the name of one possible solution (which won't work here), not the name of the problem. – Joel Coehoorn Apr 15 '10 at 20:53
  • Its the heart of the problem. – Danvil Apr 15 '10 at 20:55
  • 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 Apr 15 '10 at 21:21
  • 1
    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 Apr 15 '10 at 21:46
1

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
  • 123,721
  • 27
  • 225
  • 246