是否可以使用派生参数而不是基础参数覆盖方法?

vex*_*exe 13 c# inheritance abstract-class overriding

我陷入了这种情况:

  1. 我有一个抽象的类Ammo,有AmmoBoxClip作为孩子.
  2. 我有一个抽象的类Weapon,有FirearmMelee作为孩子.
  3. Firearm是抽象的,ClipWeaponShellWeapon孩子一样.
  4. 在里面Firearm,有一个void Reload(Ammo ammo);

问题是,a ClipWeapon可以使用a Clip和an AmmoBox来重新加载:

public override void Reload(Ammo ammo)
{
    if (ammo is Clip)
    {
        SwapClips(ammo as Clip);
    }
    else if (ammo is AmmoBox)
    {
        var ammoBox = ammo as AmmoBox;
        // AddBullets returns how many bullets has left from its parameter
        ammoBox.Set(clip.AddBullets(ammoBox.nBullets));
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,a ShellWeapon,只能用一个AmmoBox来重装.我能做到这一点:

public override void Reload(Ammo ammo)
{
    if (ammo is AmmoBox)
    {
        // reload...
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,因为即使我检查,以确保它的类型,这是不好的AmmoBox,从外面看,它看起来像一个ShellWeapon可能需要Clip为好,因为ClipAmmo也.

或者,我可以删除ReloadFirearm,并把它都ClipWeaponShellWeapon与我所需要的具体参数,可以但这样做我会失去多态性的好处,这不是我想要的.

如果我能像这样覆盖Reload内部,那不是最佳的ShellWeapon:

public override void Reload(AmmoBox ammoBox)
{
   // reload ... 
}
Run Code Online (Sandbox Code Playgroud)

当然我试过了,它没有用,我收到一个错误,说签名必须匹配或者其他什么,但这不应该是"逻辑上"有效吗?既然AmmoBoxAmmo

我应该怎么解决这个问题?一般来说,我的设计是否正确?(注意我使用的是接口IClipWeapon,IShellWeapon但是遇到了麻烦,所以我转而使用了类)

提前致谢.

Jon*_*eet 16

但这不应该是'逻辑'有效吗?

不是.您的界面说调用者可以传入任何内容 Ammo - 您限制它需要一个AmmoBox更具体的内容.

如果有人要写,你会发生什么?

Firearm firearm = new ShellWeapon();
firearm.Reload(new Ammo());
Run Code Online (Sandbox Code Playgroud)

?那应该是完全有效的代码 - 所以你想让它在执行时爆炸吗?静态类型的一半是避免这种问题.

可以Firearm的弹药类型一般是使用:

public abstract class Firearm<TAmmo> : Weapon where TAmmo : Ammo
{
    public abstract void Reload(TAmmo ammo);
}
Run Code Online (Sandbox Code Playgroud)

然后:

public class ShellWeapon : Firearm<AmmoBox>
Run Code Online (Sandbox Code Playgroud)

这可能是也可能不是一种有用的做事方式,但至少值得考虑.