【问题标题】:Why is my derived class not converible to base class?为什么我的派生类不能转换为基类?
【发布时间】:2013-04-02 18:16:07
【问题描述】:

我有以下课程:

public class Item
{
}

public class ItemCollection<TItem> : ICollection<TItem> where TItem : Item, new()
{
}

我有两个派生类:

public class Feature : Item
{
}

public class Features : ItemCollection<Feature>
{
}

我有一个管理器类来管理这些集合:

public class ItemCollectionManager<TCollection> where TCollection : ItemCollection<Item>, new()
{
}

我尝试使用这个类:

public class FeatureManager : ItemCollectionManager<Features>
{
}

但这会导致:

Features 类型必须可转换为 ItemCollection&lt;Item&gt; 才能在泛型类 ItemCollectionManager&lt;TCollection&gt; 中用作 TCollection”。

如前所述,

Features is-a ItemCollection&lt;Feature&gt;

Feature 是一个Item

我不认为接口是这项任务的理想解决方案,但如果提供理由,我愿意进行更改。

如果有人能就我做错了什么提出建议,将不胜感激。

谢谢。

【问题讨论】:

    标签: c# base derived


    【解决方案1】:

    你不能这样做……

    ItemCollection<Feature> features = ...;
    ItemCollection<Item> items = features;
    

    这是关于泛型 variance(即协变和逆变) - 它仅支持接口、委托 - 并且仅提供它们以这种方式设计(装饰有 in / @ 987654329@ - 并遵守随之而来的规则)。例如IEnumerable&lt;&gt; 是(如果您查找它的定义,您会看到 out)。有关更多详细信息,我认为最好阅读更多...

    How is Generic Covariance & Contra-variance Implemented in C# 4.0?
    Understanding Covariant and Contravariant interfaces in C#
    http://msdn.microsoft.com/en-us/library/dd799517.aspx

    在您的情况下,您可以设计一个 IItemCollection&lt;out T&gt; (interface) -(理论上)可能支持您需要的转换。但它必须是read-only有点简化,并不完全正确,但这样想更容易 - 规则有点复杂)。

    由于您将其命名为“集合”,我假设它不只是用于枚举、查看项目 - 即,如果您有某种 Add(需要 input parameters - 即 contra-variance)这与upcasting 所需的“协方差”相冲突。此外,涉及的任何其他参数都可能不允许您的界面成为协变的。


    还有一些我发的其他帖子相关...

    How to make generic class that contains a Set of only its own type or subtypes as Children?

    C# generic handlers, what am I misunderstanding?

    【讨论】:

    • +1 表示协方差和链接。而且我不知道你可以用 in / out 装饰类型参数。
    • @MalcolmO'Hare 不客气 - 是的,它在某些情况下可能很有用
    【解决方案2】:

    您需要在 ItemCollectionManager 上添加一个通用参数 TItem。

    我相信您的 ItemCollectionManager 类定义应该是这样的。

        public class ItemCollectionManager<TCollection, TItem> where TCollection : ItemCollection<TItem>, new(), 
    where TItem : Item
        {
        }
    

    您现在定义FeatureManager 类的方式完全可以接受将继承Item 的任何类添加到TCollection,因为对TCollection 的唯一限制是它包含类型的类Item。集合Features 仅接受Feature 类或继承Feature 类型的类。由于不能将Item 的基类型添加到Features,所以它不应该编译。

    【讨论】:

    • 以这种方式实现它会产生进一步的问题,而且我不认为提供 TItem 是必要的,因为无论如何它只是Item。但如果这是必需的,请您解释一下为什么?
    • 我已经添加了一些解释。如果仍然不清楚,请告诉我,我会尽力解释得更好。
    猜你喜欢
    • 2017-01-08
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 2019-09-02
    • 2011-05-07
    相关资源
    最近更新 更多