我有一个由三个抽象泛型类组成的级联,如下所示:
public abstract class SpawnTrigger<T>
public abstract class SpawnerConfig <T, S> where T : SpawnTrigger<S> {}
public abstract class Spawner<T, S> where T:SpawnerConfig<SpawnTrigger<S>, S>{}
我有三个对应的具体课程。每个继承自一个抽象的通用类,如下所示:
public class OrbSpawnTrigger : SpawnTrigger<Orb>{}
public class OrbSpawnerConfig : SpawnerConfig<OrbSpawnTrigger, Orb>{}
public class OrbSpawner : Spawner<OrbSpawnerConfig, Orb>{}
为简单起见,我在上面删除了这些类的主体。
编译器抱怨OrbSpawner
。具体来说,它抱怨:
The type 'OrbSpawnerConfig' must be convertible to 'SpawnerConfig<SpawnTrigger<Orb>,Orb>' in order to use it as parameter 'T' in the generic class 'Spawner<T,S>'
我不知道为什么会抱怨。 OrbSpawnerConfig
是SpawnerConfig<SpawnTrigger<Orb>, Orb>
:
OrbSpawnerConfig
-> SpawnerConfig<OrbSpawnTrigger, Orb>
-> SpawnerConfig<SpawnTrigger<Orb>, Orb>
有人知道这个错误吗?我在Unity项目的C#中工作。我没有意识到C#的特殊性或局限性吗?
我应该提到以下内容不会产生错误-但这不是解决方案,因为我想指定一个具体的类而不是继承的泛型摘要:
public class OrbSpawner : Spawner<SpawnerConfig<SpawnTrigger<Orb>, Orb>, Orb>
使用以下代码可以很容易地重现该错误:
namespace Test
{
public abstract class SpawnTrigger<T> {}
public abstract class SpawnerConfig<T, S> where T : SpawnTrigger<S> {}
public abstract class Spawner<T, S> where T : SpawnerConfig<SpawnTrigger<S>, S> {}
public class OrbSpawnTrigger : SpawnTrigger<Orb> { }
public class OrbSpawnerConfig : SpawnerConfig<OrbSpawnTrigger, Orb> { }
public class OrbSpawner : Spawner<OrbSpawnerConfig, Orb> {}
}
这里是重构为使用简单类名的相同代码(错误发生在ConcreteC的定义中-无法将ConcreteB用作参数V)
namespace Test
{
public abstract class A<T> {}
public abstract class B<T, U> where U : A<T> {}
public abstract class C<T, V> where V : B<T, A<T>> {}
public class ConcreteA : A<MyObj> {}
public class ConcreteB : B<MyObj, ConcreteA> {}
public class ConcreteC : C<MyObj, ConcreteB> {}
public class MyObj {}
}
感谢Dmitry Dovgopoly提供了有效的代码解决方案,并感谢PetSerAI解释了我的代码为什么有问题。据我了解,我不能使用派生的ConcreteB来满足参数V的更一般要求的约束。解决方案是使用带有out关键字的Interfaces创建一个Covariant接口。参见covariant generic interface
答案 0 :(得分:0)
如果您的参数可以是协变的,则可以通过添加接口来解决此问题
public interface ISpawnTrigger<out T>{}
public interface ISpawnerConfig<out T, S> where T : ISpawnTrigger<S>{}
public interface ISpawner<out T, S> where T : ISpawnerConfig<ISpawnTrigger<S>, S>{}
public abstract class SpawnTrigger<T> : ISpawnTrigger<T>{}
public abstract class SpawnerConfig<T, S> : ISpawnerConfig<T, S> where T : ISpawnTrigger<S>{}
public abstract class Spawner<T, S> : ISpawner<T, S> where T : ISpawnerConfig<ISpawnTrigger<S>, S>{}
public class OrbSpawnTrigger : SpawnTrigger<Orb>{}
public class OrbSpawnerConfig : SpawnerConfig<OrbSpawnTrigger, Orb>{}
public class OrbSpawner : Spawner<OrbSpawnerConfig, Orb>{}
public class Orb{}