C#: Semantics for generics?
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 everythin开发者_如何学运维g 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?
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>
.
You can't convert List<BaseClass>
to List<DerivedClass>
. Here is a recent question that deals with this issue.
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.
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());
}
精彩评论