C#:泛型的语义?
Posted
技术标签:
【中文标题】C#:泛型的语义?【英文标题】:C#: Semantics for generics? 【发布时间】:2011-02-08 13:59:23 【问题描述】:我有一个清单:
private readonly IList<IList<GameObjectController>> removeTargets;
private readonly IList<IList<GameObjectController>> addTargets;
PickUp
继承自 GameObjectController
。但是当我尝试这个时:
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();
我得到一个编译器错误:
无法从 'System.Collections.Generic.IList
' 到 'System.Collections.Generic.IList '
为什么会发生这种情况?这不是很好吗,因为PickUp
是GameObjectController
的子类?我需要像 Java 的 Map<E extends GameObjectController>
这样的东西吗?
早些时候,我遇到了类似的问题,我试图将 inventory
从 IList
隐式转换为 ICollection
。这是同样的问题吗?
【问题讨论】:
签名MoveFromListToWorld
?
【参考方案1】:
在此处查看我的其他答案:How to return an IQueryable<Something> as an IQueryable<ISomething>
短版:
请记住,IList<PickUp>
和 IList<GameObjectController>
是类型系统中两个(并且只有两个)完全不同的类。它们唯一的继承关系来自继承树的 System.Collections 分支;继承树的 GameObjectController 分支上根本没有。您不妨尝试将IList<double>
转换为IList<ArgumentNullException>
。
您可以改为调用可用于IEnumerable<T>
的Cast<T>()
扩展方法。
【讨论】:
【参考方案2】:这称为co- and contravariance,首先在 c# 4.0 中得到支持。即便如此,它也只适用于 IEnumerable 而不是 IList。
【讨论】:
协方差是一种可能的解决方案的名称(在这里不起作用),而不是问题的名称。 这是问题的核心。 不,不是。协变意味着允许类型以某种方式变化(注意词根)。 不变性——或者说一个类型不能改变——是问题的核心。 嗯,这有点哲学......您可以将“他不能做什么”(协方差)或“阻止他这样做的原因”(不变性)视为问题的核心。 【参考方案3】:您无法将List<BaseClass>
转换为List<DerivedClass>
。这是处理此问题的a recent question。
【讨论】:
好吧,如果你编写代码来转换它,你就可以转换它——你只是不能转换它。【参考方案4】:基础对象列表当然可以包含派生对象的项目。但是,我无法从您的代码中收集到的正是您正在做的事情。你有一个IList<IList<class>>
,然后你的方法的实现对我们是不可见的。但是像下面这样的代码肯定有效(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);
也许您正在尝试以下场景?这是您拥有基础项目列表和派生对象列表列表的地方?如果是这样,您可以像下面这样投射。
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());
【讨论】:
没错。我正在尝试执行上述操作。我想怎么做?以上是关于C#:泛型的语义?的主要内容,如果未能解决你的问题,请参考以下文章