I have four interfaces:
public interface IBasicBoat
{
Hull BoatHull { get; set; }
}
public interface ISailBoat : IBasicBoat
{
List<Sail> Sails { get; set; }
}
public interface IMotorBoat : IBasicBoat
{
Engine Motor { get; set; }
}
public interface IGenericBoat : ISailBoat, IMotorBoat
{
}
and one class:
public class GenericBoat : IGenericBoat
{
public Hull BoatHull { get; set; }
public List<Sail> Sails { get; set; }
public Engine Motor { get; set; }
}
I want my algorithm to work differently on ISailBoat
s and IMotorBoat
s.
Say I have these two objects:
ISailBoat z_objSailBoat = new GenericBoat()
{
BoatHull = new Hull(),
Sails = new List<Sail>()
};
IMotorBoat z_objMotorBoat = new GenericBoat()
{
BoatHull = new Hull(),
Motor = new Engine()
};
and this method:
public void CheckBuoyancy(IBasicBoat p_objBoat)
{
// [...]
}
that is called twice: CheckBuoyancy(z_objSailBoat)
and CheckBuoyancy(z_objMotorBoat)
.
Inside CheckBuoyancy()
, I want to be able to tell whether p_objBoat
is an ISailBoat
so I can check the sails.
I've tried
if (p_objBoat is ISailBoat z_objSailBoatToCheck)
{
// do something with z_objSailBoatToCheck.Sails
}
but both z_objSailBoat
and z_objMotorBoat
pass that test.
z_objMotorBoat is ISailBoat
return true?
(1a. Is it because z_objMotorBoat
is created as a GenericBoat
, or is it more complicated?)p_objBoat
is an ISailBoat
?The obvious solution to 2. would be to create more classes like SailBoat
and MotorBoat
so I'd have two different constructors, but I'd like to avoid that. (If only because my actual case is noticeably more complicated.)
The reason is that GenericBoat implements both interfaces and runtime will always evaluate it that way.
You might check that by revisiting the code.
Interfaces:
public interface IBoat
{
Hull BoatHull { get; set; }
Buoyancy CheckBuoyancy();
}
public interface ISailBoat : IBoat
{
List<Sail> Sails { get; set; }
}
public interface IMotorBoat : IBoat
{
Engine Motor { get; set; }
}
Classes:
public abstract class Boat : IBoat
{
Hull BoatHull { get; set; }
public virtual Buoyancy CheckBuoyancy() {
// Calculate buoyancy if both boat types use same algorithm.
// If not you might want to change virtual modifier to abstract to force each concrete type to implement its own calculation.
}
}
public class MotorBoat : Boat, IMotorBoat
{
Engine Motor { get; set; }
public override Buoyancy CheckBuoyancy() {
// In case you need to use different way to calculate buoyancy
}
}
public class SailBoat : Boat, ISailBoat
{
List<Sail> Sails { get; set; }
public override Buoyancy CheckBuoyancy() {
// In case you need to use different way to calculate buoyancy
}
}
Usage:
IBoat boat1 = new SailBoat()
{
BoatHull = new Hull(),
Sails = new List<Sail>()
};
IBoat boat2 = new MotorBoat()
{
BoatHull = new Hull(),
Motor = new Engine()
};
var boatBuoyancy1 = boat1.CheckBuoyancy();
var boatBuoyancy2 = boat2.CheckBuoyancy();
if(boat1 is ISailBoat sailBoat) {
var sailsCount = sailBoat.Sails.Count();
}
if(boat2 is IMotorBoat motorBoat) {
var horsePower = motorBoat.Motor.HorsePower;
}