Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
338 views
in Technique[技术] by (71.8m points)

c# - Is it possible to override a method with a derived parameter instead of a base one?

I'm stuck in this situation where:

  1. I have an abstract class called Ammo, with AmmoBox and Clip as children.
  2. I have an abstract class called Weapon, with Firearm and Melee as children.
  3. Firearm is abstract, with ClipWeapon and ShellWeapon as children.
  4. Inside Firearm, there's a void Reload(Ammo ammo);

The problem is that, a ClipWeapon could use both a Clip and an AmmoBox to reload:

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));
    }
}

But a ShellWeapon, could only use an AmmoBox to reload. I could do this:

public override void Reload(Ammo ammo)
{
    if (ammo is AmmoBox)
    {
        // reload...
    }
}

But this is bad because, even though I'm checking to make sure it's of type AmmoBox, from the outside, it appears like a ShellWeapon could take a Clip as well, since a Clip is Ammo as well.

Or, I could remove Reload from Firearm, and put it both ClipWeapon and ShellWeapon with the specific params I need, but doing so I will lose the benefits of Polymorphism, which is not what I want to.

Wouldn't it be optimal, if I could override Reload inside ShellWeapon like this:

public override void Reload(AmmoBox ammoBox)
{
   // reload ... 
}

Of course I tried it, and it didn't work, I got an error saying the signature must match or something, but shouldn't this be valid 'logically'? since AmmoBox is a Ammo?

How should I get around this? And in general, is my design correct? (Note I was using interfaces IClipWeapon and IShellWeapon but I ran into trouble, so I moved to using classes instead)

Thanks in advance.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

but shouldn't this be valid 'logically'?

No. Your interface says that the caller can pass in any Ammo - where you're restricting it to require an AmmoBox, which is more specific.

What would you expect to happen if someone were to write:

Firearm firearm = new ShellWeapon();
firearm.Reload(new Ammo());

? That should be entirely valid code - so do you want it to blow up at execution time? Half the point of static typing is to avoid that sort of problem.

You could make Firearm generic in the type of ammo is uses:

public abstract class Firearm<TAmmo> : Weapon where TAmmo : Ammo
{
    public abstract void Reload(TAmmo ammo);
}

Then:

public class ShellWeapon : Firearm<AmmoBox>

That may or may not be a useful way of doing things, but it's at least worth considering.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...