简体   繁体   English

更复杂的扩展 generics 到 C#

[英]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. ModularAIAbstractAI<IShipController>IShipControllerIRotableWeaponController ,但我得到一个错误。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM