Reputation: 301
I have a weapon
class, projectile
class and ballistic weapon
class that inherits from weapon
, ballistic projectile
class inherits from projectile
and weapon
class has a projectile property that gets and sets the projectile for the weapon.
ballistic weapon inherits this however ballistic weapon wouldn't have just any weapon it has a ballistic projectile (distinct from say a laser projectile that wouldn't have a projectile speed because it is instant impact)
So if I choose to override the property of weapon, the setter could cause issues because
public Projectile weaponprojectile
{
// getter/setter
}
takes just a generic Projectile. The getter override would work ok because returning a ballstic projectile is still returning a base projectile, it has all the things projectile does and then some. However the setter wouldn't absolutely be ok. Not just any projectile can be set as a ballistic projectile.
So if I use an override is it the right way to confirm the type of ballistic and static convert or should I try something else?
If i don't use a override but make a new setter I'm worried I'd end up with this weapon that had 2 nearly indentical properties,
its projectile and its ballistic projectile which is basically a projectile plus some other stuff and really having a get ballistic projectile is pointless.
I'm new to using inheritance so if someone could give me guidance basically on what you do if you have an abstract class with a generic variable and you inherit that class and variable and have a more specific type of variable.
Upvotes: 2
Views: 245
Reputation: 52147
You could use covariance to allow for "specialized" projectiles in weapon properties, while still keeping the ability to treat the weapons as part of the same hierarchy:
interface IProjectile {
string Name { get; }
}
// Note the `out` keyword below:
interface IWeapon<out TProjectile> where TProjectile : IProjectile {
TProjectile Projectile { get; }
}
class BallisticMissile : IProjectile {
public double Speed { get; set; }
public string Name { get { return "ballistic missile"; } }
}
class BallisticWeapon : IWeapon<BallisticMissile> {
public BallisticMissile Projectile { get; set; }
}
class LaserBeam : IProjectile {
public double WaveLength;
public string Name { get { return "laser beam"; } }
}
class LaserWeapon : IWeapon<LaserBeam> {
public LaserBeam Projectile { get; set; }
}
class Program {
static void Main(string[] args) {
// Manipulate the ballistic weapon in its own specific way:
var ballisticWeapon = new BallisticWeapon();
ballisticWeapon.Projectile = new BallisticMissile();
ballisticWeapon.Projectile.Speed = 2000;
// Manipulate the laser weapon in its own specific way:
var laserWeapon = new LaserWeapon();
laserWeapon.Projectile = new LaserBeam();
laserWeapon.Projectile.WaveLength = 400;
// But you can still use both of them as an IWeapon<IProjectile>:
var weapons = new List<IWeapon<IProjectile>>();
weapons.Add(ballisticWeapon);
weapons.Add(laserWeapon);
foreach (var weapon in weapons)
Console.WriteLine(weapon.Projectile.Name);
}
}
Upvotes: 2
Reputation: 518
You may want to post all classes involved. If I understand you I would think you have some Fire method in the Weapon class (or some method that uses weaponprojectile). You probably want to override that method. Having to detect the type and take an action is not the best design. It is better to encapsulate what changes (in this case the code doing the Fire/Attack/Whatever) and the Setter. Example
public class BalisticWeapon
{
public BalisticWeapon(){}
public override BalisticProjectile weaponprojectile
{
get { return Base.weaponprojectile; }
set { Base.Weaponprojectile = value; }
}
public override void Fire()
{
//Handle special case for Firing BalisticProjectile
}
}
Upvotes: 1
Reputation: 1931
There are lots of ways to design what you are looking for. If it was me I would probably make use of interfaces to avoid the inheritance issues you are describing. I may also make these different types of weapons described in an xml file that gets loaded at runtime. However something like this would work base of what you are describing:
public interface IWeapon
{
int WeaponDamage { get; }
}
public interface IBalisticWeapon
{
int BallisticDamage { get; }
}
public interface IProjectile
{
int ProjectileDamage { get; }
}
public abstract class WeaponBase: IWeapon
{
public virtual int WeaponDamage { get { return 100; } }//base damage
}
public class Arrow : WeaponBase, IProjectile, IBalisticWeapon
{
public override int WeaponDamage { get { return this.BallisticDamage; } }
public int BallisticDamage { get { return 10; } }
public int ProjectileDamage { get { return this.BallisticDamage; } }
}
public class BattleAxe : WeaponBase
{
//this inherits Weapon Damage from WeaponBase
}
public class Rock : WeaponBase, IProjectile
{
public override int WeaponDamage { get { return this.ProjectileDamage; } }
public int ProjectileDamage { get { return 10; } }
}
class Program
{
static WeaponBase GetWeapon()
{
return new Arrow();
}
static void Main(string[] args)
{
int damage = 0;
IWeapon weapon = GetWeapon();
if (weapon is IProjectile)
{
damage = (weapon as IProjectile).ProjectileDamage;
}
else if (weapon is IBalisticWeapon)
{
damage = (weapon as IBalisticWeapon).BallisticDamage;
}
else
{
damage = (weapon as IWeapon).WeaponDamage;
}
}
}
Upvotes: 1