与 C# 泛型、T、抽象有点混淆?
A little bit confusion with C# Generics, T, Abstraction ?
我是 Unity 的 C# 游戏制作者。我有收藏管理系统。
CollectableManager
public List<CollectableParent<Collectable>> collactableParentsList;
收藏父母
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>
问题
CollectableManager 中的 "collactableParentsList" 不接受 SpawnPointParentDefinedCollectableParent<Collectable_Money>
作为 T 定义为 "Collectable_Money" 的项,它是从 "Collectable" 派生的。如果我这样做 SpawnPointParentDefinedCollectableParent<Collectable>
,它会被接受为列表中的项目。
这里的问题是,尽管 Collectable_Money
是 Collectable
的子 class,但 而不是 使 SpawnPointParentDefinedCollectableParent<Collectable_Money>
CollectableParent<Collectable>
.
的子class
使用通用接口或许可以解决这个问题。如果我们将 CollectableParent<T>
更改为接口,并通过 out
修饰符将其定义为 T
中的 covariant。 (你还没有提供CollectableRelatedMonoBehaviour
的定义,但也需要转换成接口):
public interface ICollectableParent<out T> : ICollectableRelatedMonoBehaviour where T : Collectable
如果您将列表定义为:
public static List<ICollectableParent<Collectable>> collectableParentsList;
然后就可以成功添加类型为SpawnPointParentDefinedCollectableParent<Collectable_Money>
的项目了。
这里的关键部分是 ICollectableParent<T>
接口在 T
中是协变的。这使得传递实现 ICollectableParent<Collectable_Money>
的实例成为可能,其中需要 ICollectableParent<Collectable>
。
在 T
中将接口定义为协变确实引入了一些限制,具体而言(并且正如用于指示协变的 out
修饰符所暗示的那样),类型 T
只能是用作接口方法的 return 值。例如:
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
我是 Unity 的 C# 游戏制作者。我有收藏管理系统。
CollectableManager
public List<CollectableParent<Collectable>> collactableParentsList;
收藏父母
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>
问题
CollectableManager 中的"collactableParentsList" 不接受 SpawnPointParentDefinedCollectableParent<Collectable_Money>
作为 T 定义为 "Collectable_Money" 的项,它是从 "Collectable" 派生的。如果我这样做 SpawnPointParentDefinedCollectableParent<Collectable>
,它会被接受为列表中的项目。
这里的问题是,尽管 Collectable_Money
是 Collectable
的子 class,但 而不是 使 SpawnPointParentDefinedCollectableParent<Collectable_Money>
CollectableParent<Collectable>
.
使用通用接口或许可以解决这个问题。如果我们将 CollectableParent<T>
更改为接口,并通过 out
修饰符将其定义为 T
中的 covariant。 (你还没有提供CollectableRelatedMonoBehaviour
的定义,但也需要转换成接口):
public interface ICollectableParent<out T> : ICollectableRelatedMonoBehaviour where T : Collectable
如果您将列表定义为:
public static List<ICollectableParent<Collectable>> collectableParentsList;
然后就可以成功添加类型为SpawnPointParentDefinedCollectableParent<Collectable_Money>
的项目了。
这里的关键部分是 ICollectableParent<T>
接口在 T
中是协变的。这使得传递实现 ICollectableParent<Collectable_Money>
的实例成为可能,其中需要 ICollectableParent<Collectable>
。
在 T
中将接口定义为协变确实引入了一些限制,具体而言(并且正如用于指示协变的 out
修饰符所暗示的那样),类型 T
只能是用作接口方法的 return 值。例如:
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