Is it fine to typecast from one implementation type to another while using an object? I've a simple code base with few 'weapon' concrete classes which implements different contracts in order to be used by its clients.

My contracts:

public interface IWeaponPrimaryAttack
{
    void DoAttack();
}
public interface IWeaponSecondaryAttack
{
    void DoSecondaryAttack();
}
public interface IReloadable
{
    void Reload();
}


Concrete implementation or the actual weapons:

public class Katana : IWeaponPrimaryAttack, IWeaponSecondaryAttack
{
    public void DoAttack(){Console.WriteLine ("Swing");}
    public void DoSecondaryAttack() {Console.WriteLine ("Stab");}
}
public class ShotGun : IWeaponPrimaryAttack, IReloadable
{
    public void DoAttack(){Console.WriteLine ("Swing");}
    public void Reload() {//reload it}
}


Clients that uses these concrete classes:

public class PrimaryAttack
{
    private IWeaponPrimaryAttack _attack;
    public PrimaryAttack(IWeaponPrimaryAttack attack)
    {
        _attack = attack;
    }
    public void DoAttack()
    {
        _attack.DoAttack();
    }
}
public class SecondaryAttack
{
    private IWeaponSecondaryAttack _attack;
    public SecondaryAttack(IWeaponSecondaryAttack attack)
    {
        _attack = attack;
    }
    public void DoSecondaryAttack()
    {
        _attack.DoSecondaryAttack();
    }
}
public class WeaponReload
{
    private IReloadable _reloader;
    public WeaponReload(IReloadable reloader)
    {
        _reloader = reloader;
    }
    public void Reload()
    {
        _reloader.Reload();
    }
}


New of course the instantiation of concrete class only be known when the user selects one among many weapons(one among ShotGun, Katana, etc).

Let say the use has selected ShotGun as the weapon, based on the selection it might go like this:

IWeaponPrimaryAttack weapon = new ShotGun(); // get it from a factory
PrimaryAttack primaryAttack = new PrimaryAttack(weapon);
primaryAttack.DoAttack();


Now for the WeaponReload have to do a typecast here in order to use it.

WeaponReload reloader = new WeaponReload ((IReloadable)weapon);
reloader.Reload();


I have questions around it,


Should I really have to end up typecasting eventually?
Or there is a better way to handle this object creation part.
Or there is entirely a better design that I can come up with which
does not necessarily ends up in casting.
Or casting it like this is totally fine.
Composition over inheritance and Strategy Pattern

I would, instead of having differents weapons implementing differents interfaces defining their behaviour, create classes that holds the logic of the behaviour

Let's consider a weapon can have a primary attack, a secondary one and reload.

The class could be defined as such :

abstract class Weapon
{
    public IWeaponPrimaryAttack WeaponPrimaryAttack { get; set; }
    public IWeaponSecondaryAttack WeaponSecondaryAttack { get; set; }
    public IReloadable Reloadable { get; set; }
}


Now, we can define classes that holds differents behaviours of the interfaces.

In example :

public class SlashAttack : IWeaponPrimaryAttack
{
    public void DoAttack()
    {
        Console.WriteLine("Performing a slash attack");
    }
}

public class StabAttack : IWeaponSecondaryAttack
{
    public void DoSecondaryAttack()
    {
        Console.WriteLine("Performing a stab attack");
    }
}

public class Shooting12Caliber : IWeaponPrimaryAttack
{
    public void DoAttack()
    {
        Console.WriteLine("Bam !");
    }
}

public class Caliber12Reloader : IReloadable
{
    public void Reload()
    {
        Console.WriteLine("Reloading caliber 12 !");
    }
}

public class ShootingWith556 : IWeaponPrimaryAttack
{
    public void DoAttack()
    {
        Console.WriteLine("Bam (version 5.56) !");
    }
}

public class Caliber556Reloader : IReloadable
{
    public void Reload()
    {
        Console.WriteLine("Reloading caliber 5.56 !");
    }
}


And now, you can use theses class as properties in differents weapon classes.

You'll implement once the methods and can use the same for differents weapons : 

public class Katana : Weapon
{
    public Katana()
    {
         WeaponPrimaryAttack = new SlashAttack();
         WeaponSecondaryAttack = new StabAttack();
    }
}

public class Machete : Weapon
{
    public Machete()
    {
         WeaponPrimaryAttack = new SlashAttack();
    }
}

public class Shotgun : Weapon
{
    public Shotgun()
    {
         WeaponPrimaryAttack = new Shooting12Caliber();
         Reloadable = new Caliber12Reloader();
    }
}

public class AssaultRifleWithBayonet : Weapon
{
    public AssaultRifleWithBayonet()
    {
         WeaponPrimaryAttack = new ShootingWith556();
         WeaponSecondaryAttack = new StabAttack();
         Reloadable = new Caliber556Reloader();
    }
}


Now, your methods implementations are refactored within classes and are reusable. You don't need to typecast to check if this or that interface is implemented.

if (weapon.Reloadable != null)
{
    weapon.Reloadable.Reload();
}
else
{
    Console.WriteLine("This weapon isn't meant to be reloaded");
}

/*
This works too if you want to omit the Reloadable != null

public class CannotReload : IReloadable
{
    public void Reload()
    {
        Console.WriteLine("This weapon isn't meant to be reloaded");
    }
}
*/