【问题标题】:A little bit confusion with C# Generics, T, Abstraction ?与 C# 泛型、T、抽象有点混淆?
【发布时间】:2018-09-23 09:38:39
【问题描述】:

我是 Unity 的 C# 游戏制作者。我有收藏管理系统。

CollectableManager

public List<CollectableParent<Collectable>> collactableParentsList;

CollectableParent

public class CollectableParent<T> : CollectableRelatedMonoBehaviour where T : Collectable

SpawnPointDefinedCollectableParent

public class SpawnPointParentDefinedCollectableParent<T> : CollectableParent<T> where T : Collectable

收藏

public abstract class Collectable : CollectableRelatedMonoBehaviour, IHasPlayableSound

Collectable_Money

public class Collectable_Money : Collectable

CollectableParent_Money

public class CollectableParent_Money : SpawnPointParentDefinedCollectableParent<Collectable_Money>

问题

当 T 定义为“Collectable_Money”时,CollectableManager 中的“collactableParentsList”不接受SpawnPointParentDefinedCollectableParent&lt;Collectable_Money&gt; 作为项目,它是从“Collectable”派生的。如果我这样做SpawnPointParentDefinedCollectableParent&lt;Collectable&gt;,它将被接受为列表中的项目。

【问题讨论】:

    标签: c# oop unity3d generics abstraction


    【解决方案1】:

    这里的问题是,即使Collectable_MoneyCollectable 的子类,不会使SpawnPointParentDefinedCollectableParent&lt;Collectable_Money&gt; 成为CollectableParent&lt;Collectable&gt; 的子类。

    可以通过使用通用接口来解决这个问题。如果我们将CollectableParent&lt;T&gt; 更改为接口,并通过out 修饰符将其定义为T 中的协变。 (您还没有提供CollectableRelatedMonoBehaviour 的定义,但它也需要转换为接口):

    public interface ICollectableParent<out T> : ICollectableRelatedMonoBehaviour where T : Collectable
    

    如果您随后将列表定义为:

    public static List<ICollectableParent<Collectable>> collectableParentsList;
    

    然后你就可以成功的添加SpawnPointParentDefinedCollectableParent&lt;Collectable_Money&gt;类型的项目了。

    这里的关键部分是ICollectableParent&lt;T&gt; 接口在T 中是协变的。这使得传递一个实现 ICollectableParent&lt;Collectable_Money&gt; 的实例成为可能,而 ICollectableParent&lt;Collectable&gt; 是预期的。

    T 中将接口定义为协变确实引入了一些限制,特别是(正如用于指示协变的out 修饰符所暗示的那样),T 类型只能用作接口的返回值方法。例如:

    public interface ICollectableParent<out T> : ICollectableRelatedMonoBehaviour where T : Collectable
    {
        // This is allowed - T is used as a return type
        T GetChild();
        // This is *not* allowed - T is used as a parameter
        void SetChild(T child);
    }
    

    您可以在此处阅读有关协方差及其逆(逆变)的更多信息:Difference between Covariance & Contra-variance

    【讨论】:

    • 感谢您的出色回答,void SetChild(T child) 的限制确实影响了我,我可能会重新考虑整个设计,看起来泛型在这种情况下限制了我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-11
    • 1970-01-01
    • 2019-10-10
    • 2017-07-01
    • 2012-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多