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'

为什么会发生这种情况?这不是很好吗,因为PickUpGameObjectController 的子类?我需要像 Java 的 Map&lt;E extends GameObjectController&gt; 这样的东西吗?

早些时候,我遇到了类似的问题,我试图将 inventoryIList 隐式转换为 ICollection。这是同样的问题吗?

【问题讨论】:

签名MoveFromListToWorld? 【参考方案1】:

在此处查看我的其他答案:How to return an IQueryable<Something> as an IQueryable<ISomething>

短版:

请记住,IList&lt;PickUp&gt;IList&lt;GameObjectController&gt; 是类型系统中两个(并且只有两个)完全不同的类。它们唯一的继承关系来自继承树的 System.Collections 分支;继承树的 GameObjectController 分支上根本没有。您不妨尝试将IList&lt;double&gt; 转换为IList&lt;ArgumentNullException&gt;

您可以改为调用可用于IEnumerable&lt;T&gt;Cast&lt;T&gt;() 扩展方法。

【讨论】:

【参考方案2】:

这称为co- and contravariance,首先在 c# 4.0 中得到支持。即便如此,它也只适用于 IEnumerable 而不是 IList。

【讨论】:

协方差是一种可能的解决方案的名称(在这里不起作用),而不是问题的名称。 这是问题的核心。 不,不是。协变意味着允许类型以某种方式变化(注意词根)。 不变性——或者说一个类型不能改变——是问题的核心。 嗯,这有点哲学......您可以将“他不能做什么”(协方差)或“阻止他这样做的原因”(不变性)视为问题的核心。 【参考方案3】:

您无法将List&lt;BaseClass&gt; 转换为List&lt;DerivedClass&gt;。这是处理此问题的a recent question。

【讨论】:

好吧,如果你编写代码来转换它,你就可以转换它——你只是不能转换它。【参考方案4】:

基础对象列表当然可以包含派生对象的项目。但是,我无法从您的代码中收集到的正是您正在做的事情。你有一个IList&lt;IList&lt;class&gt;&gt;,然后你的方法的实现对我们是不可见的。但是像下面这样的代码肯定有效(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#:泛型的语义?的主要内容,如果未能解决你的问题,请参考以下文章

C# 泛型的使用

C#进阶C# 泛型

(整理)C#基础知识_泛型的实现

C#泛型

c# 泛型的静态成员

c# 泛型的静态成员