[英]More complex extending generics in C#
I have two trees of classes with generics and I cannot figure out one thing, that I know how to solve in Java with <? extends...>
我有两个类树 generics 我不知道一件事,我知道如何在 Java <? extends...>
解决<? extends...>
. <? extends...>
.
First AI tree:第一个 AI 树:
abstract class AbstractAI<TCtrl> : MonoBehaviour where TCtrl: IRotableWeaponController
abstract class AbstractShipAI : AbstractAI<IShipController>
class ModularAI : AbstractShipAI
Some other classes that extend AbstractAI and use various modules
Modules tree:模块树:
abstract class AbstractModule<TAi, TCtrl> : AIModule where TAi: AbstractAI<TCtrl> where TCtrl: IRotableWeaponController
{
public virtual void Init(TAi parent)
}
class ShootModule: AbstractModule<AbstractAI<IRotableWeaponController>, IRotableWeaponController>
Some other modules that extend AbstractModule and can be used only with some AIs, that have required capabilities
Used controller interfaces tree:使用的 controller 接口树:
interface IRotableWeaponController
interface IShipController: IRotableWeaponController
Other interfaces extending IRotableWeaponController...
The issue is:问题是:
class ModularAI : AbstractShipAI
{
public ShootModule shootModule;
protected override void Start()
{
shootModule.Init(this); // Error: Argument type 'ModularAI' is not assignable to parameter type 'AbstractAI<IRotableWeaponController>'
}
}
ModularAI
is AbstractAI<IShipController>
, IShipController
is IRotableWeaponController
, but I get an error. ModularAI
是AbstractAI<IShipController>
, IShipController
是IRotableWeaponController
,但我得到一个错误。
In Java I would do:在 Java 我会这样做:
abstract class AbstractModule<TAi, TCtrl> : AIModule where TAi: AbstractAI<? extends TCtrl> where TCtrl: IRotableWeaponController
I know it's kind of complex and there is probably a better way to design it (and I may eventually get to it one day) but I want to know, how to solve this issue.我知道它有点复杂,并且可能有更好的设计方法(我最终可能有一天会得到它)但我想知道如何解决这个问题。 Please, how can I make it work?请问,我怎样才能使它工作?
I made an easier example to illustrate your issue:我做了一个更简单的例子来说明你的问题:
class Fruit { }
class Apple : Fruit { }
class FruitMaker<T> where T : Fruit { }
class Program
{
static void HandleFruit(FruitMaker<Fruit> fruitMaker) { }
static void Main()
{
FruitMaker<Apple> appelMaker = new FruitMaker<Apple>();
FruitMaker<Fruit> fruitMaker = appelMaker; //cannot convert from 'FruitMaker<Apple>' to 'FruitMaker<Fruit>'
HandleFruit(fruitMaker);
}
}
What you need is generics covariance, you need to pass FruitMaker<Apple>
to a method that expects FruitMaker<Fruit>
.您需要的是 generics 协方差,您需要将FruitMaker<Apple>
传递给期望FruitMaker<Fruit>
的方法。 This is enabled with the out
keyword, what you want is class FruitMaker<out T> where T: Fruit { }
, but you can't do that because FruitMaker
is not an interface.这是通过out
关键字启用的,您想要的是class FruitMaker<out T> where T: Fruit { }
,但您不能这样做,因为FruitMaker
不是接口。 You can solve this as follows:您可以按以下方式解决此问题:
class Fruit { }
class Apple : Fruit { }
interface IFruitMaker<out T> where T : Fruit { }
class FruitMaker<T> : IFruitMaker<T> where T : Fruit { }
class Program
{
static void HandleFruit(IFruitMaker<Fruit> fruitMaker) { }
static void Main()
{
FruitMaker<Apple> appelMaker = new FruitMaker<Apple>();
IFruitMaker<Fruit> fruitMaker = appelMaker; //this is allowed thanks to the out keyword
HandleFruit(fruitMaker);
}
}
Notice that I introduced an interface just to be able to add the out
keywork.请注意,我引入了一个接口只是为了能够添加out
键。
You can use Covariance by inserting an interface in place of the abstract class, appropriately marked for it:您可以通过插入一个接口代替抽象 class 来使用协方差,并为其适当标记:
interface IAbstractAI<out TCtrl> where TCtrl : IRotableWeaponController {
}
abstract class AbstractAI<TCtrl> : MonoBehaviour, IAbstractAI<TCtrl> where TCtrl : IRotableWeaponController {
}
abstract class AbstractModule<TAi, TCtrl> : AIModule where TAi : IAbstractAI<TCtrl> where TCtrl : IRotableWeaponController {
public virtual void Init(TAi parent) {
}
}
class ShootModule : AbstractModule<IAbstractAI<IRotableWeaponController>, IRotableWeaponController> {
}
class ModularAI : AbstractShipAI {
public ShootModule shootModule;
protected override void Start() {
shootModule.Init(this); // Error: Argument type 'ModularAI' is not assignable to parameter type 'AbstractAI<IRotableWeaponController>'
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.