C#:指定函数arg必须从一个类继承,并实现一个接口?

C#:指定函数arg必须从一个类继承,并实现一个接口?,c#,oop,inheritance,interface,C#,Oop,Inheritance,Interface,我正在制作一个游戏,其中每个参与者都由一个GameObjectController表示。可以参与战斗的游戏对象工具ICombatant。如何指定战斗函数的参数必须继承自GameObjectController并实现ICombatant?或者这是否表明我的代码结构不好 public void ComputeAttackUpdate(ICombatant attacker, AttackType attackType, ICombatant victim) 在上面的代码中,我希望攻击者和受害者从G

我正在制作一个游戏,其中每个参与者都由一个
GameObjectController
表示。可以参与战斗的游戏对象工具
ICombatant
。如何指定战斗函数的参数必须继承自
GameObjectController
并实现
ICombatant
?或者这是否表明我的代码结构不好

public void ComputeAttackUpdate(ICombatant attacker, AttackType attackType, ICombatant victim)

在上面的代码中,我希望
攻击者
受害者
GameObjectController
继承并实现
ICombatant
。这在语法上是可能的吗?

只有当
GameObjectController
本身实现了
ICombatant
时,才在语法上是可能的;否则,我会说你有一个设计问题

接口用于定义某些对象上可用的操作;基类标识该对象是什么。您只能选择其中一个。如果接受
ICombatant
接口作为参数是不够的,则可能表明
ICombatant
的定义过于狭窄(即不支持需要它执行的所有操作)

我必须看看你试图用这个物体做什么的细节,以便更深入地研究

如果您改为这样做会怎么样:

public class GameObjectControllerCombatant : GameObjectController, ICombatant
{
    // ...
}

然后从中派生战斗人员类,而不是直接从
GameObjectController
派生。在我看来,它仍然像是打破了封装,而名称的尴尬是一个强烈的迹象,表明你的战斗类正在违反。。。但它会起作用。

想必所有的iCombatant都必须是GameObjectController?如果是这样,您可能希望创建一个新接口IGameObjectController,然后声明:

interface IGameObjectController
{
    // Interface here.
}

interface ICombatant : IGameObjectController
{
    // Interface for combat stuff here.
}

class GameObjectController : IGameObjectController
{
    // Implementation here.
}

class FooActor : GameObjectController, ICombatant
{
    // Implementation for fighting here.   
}

嗯,有点。您可以编写一个通用方法:

public void ComputeAttackUpdate<T>(T attacker, AttackType type, T victim)
    where T : GameObjectController, ICombatant
public void ComputeAttackUpdate(T攻击者、攻击类型、T受害者)
其中T:GameObjectController,ICombatant
这意味着
T
必须满足您需要的两个约束。但这相当可怕——如果攻击者和受害者可能是不同(有些不相关)的类型,那么您必须在两个类型参数中将其设置为泛型


然而,我个人会尝试一个更自然的解决方案。当然,这不是我所处的情况。如果你需要以两种不同的方式来看待一个参数,也许你真的需要两种不同的方法?

我想说,这可能表明你可以以某种方式重新构造,比如,攻击者和受害者继承自一个基本战斗类,它继承自GameObjectController并实现ICombatant

但是,您可以执行以下操作

ComputeAttackUpdate<T,U>(T attacker, AttackType attackType, U victim)
      where T: ICombatant, GameObjectController
      where U: ICombatant, GameObjectController
ComputeAttackUpdate(T攻击者、攻击类型攻击类型、U受害者)
其中T:ICombatant,GameObjectController
其中U:ICombatant,GameObjectController

尽管我可能不会。

如果您控制所有相关类,并且GameObjectController没有定义任何字段,最干净的方法是定义一个IGameObjectController(其属性和方法与GameObjectController的属性和方法相匹配)和一个ICombatantGameObjectContoller(它同时来自IGameObjectController和ICombatant)。在需要两个接口的情况下可用的每个类都必须显式声明为实现ICombatantGameObjectController,即使添加该声明不需要添加任何额外的代码。如果这样做,则可以使用ICombatantGameObjectController类型的参数、字段和变量,而无需区分邪教


如果您不能如上所述设置类和接口,Jon Skeet提供的方法通常是一种很好的方法,但有一个很糟糕的警告:要调用Skeet先生的ComputeAttackUpdate之类的泛型函数,编译器必须能够确定一种类型,它知道该类型与在nd和所有约束。如果有GameObjectController的后代实现了ICombatant,但不是从也实现了GameObjectController的公共基类型派生的,则可能很难将此类对象存储在字段中,然后将其传递给泛型例程。有一种方法,如果需要,我可以解释,但是这有点棘手。

我可以让
ICombatant
有一个
GameObjectController
的getter,但这似乎是不必要的膨胀。代码总是
public GameObjectController{get{return this;}
@Rosarch:如果
ICombatant
接口实际上可以实现这样一个属性,那么它似乎表明
GameObjectController
实际上已经实现了
ICombatant
(或者可以实现);因此,只需接受一个
GameObjectController
参数,您就不需要
ICombatant
。进一步思考,您的困境可能表明与此相反;实现
ICombatant
的类有太多的责任。从逻辑上看,
ICombatant
实际上是与“控制器”相同的实例我真的很想看到你假设在方法体中编写的代码,如果这可以在签名中实现的话。这正是我想要的,除了
GameObjectController
是一个类,而不是一个接口。有没有办法对一个类这样做,或者我必须将它重新构造成一个接口?@Rosarch:你需要重新构造ure。这是一个众所周知的重构操作,称为“提取接口”,可以自动执行。你也可以很容易地手动执行。实际上,通用方法的全部要点是,你在一个方法中拥有所有共享逻辑。例如,我有一个方法,它执行HTTPRequest,并将响应转换为与使用XMLSerializer((typeof(T))的类型相同