c# 8+ Inheritance (with override) combined with default interface implementation

Viewed 23

I have an "inheritance-tree" which looks like this: enter image description here

Which means: Device is the base class where DeviceType1 and Target(DevX)/TargetWithTeststand(DevX)/Simulation(DevX) inherit of.

Lets assume one function (i.e. Press power button) is different between Target, Sim and TargetWithTeststand but common for TargetWithTeststand(Dev1 and Dev2).

Then the the code could look like this:

public abstract class Device
{
    public virtual void ReadMotorSpeed()
    {
        throw new NotImplementedException();
    }

    public virtual void UsePowerButton()
    {
        throw new NotImplementedException();
    }
}

public abstract class DeviceType1 : Device
{
    public override ReadMotorSpeed()
    {
         // Return motor speed of motor of dev1
    }
}

public abstract class DeviceType2 : Device
{
    public override ReadMotorSpeed()
    {
         // Return motor speed of motor of dev2
    }
}

public sealed class TargetWithTeststandDev1 : DeviceType1
{
    public override void UsePowerButton()
    {
        // Do something
    }
}

public sealed class TargetWithTeststandDev2 : DeviceType2
{
    public override void UsePowerButton()
    { 
        // Do something
    }
}

But i would like to have the common code for TargetWithTeststandDevX at a common place. My first idea was to use default interface implementation, but this does not allow "override" which makes it really unusable in this szenario. Atm I'm just using a specific class: CommonTeststandFunctionMethods like this:

public sealed class TargetWithTeststandDev2 : DeviceType2
{
    public override void UsePowerButton()
    { 
        CommonTeststandFunctionMethods.UsePowerButton();
    }
}

But this feels wrong... Any better idea?

1 Answers

It's the TargetWithTeststandDev1 : DeviceType1 relationship that bothers me the most.

I suspect you need something more like this:

public abstract class DeviceBase
{
    public virtual void ReadMotorSpeed() { throw new NotImplementedException(); }
    public virtual void UsePowerButton() { throw new NotImplementedException(); }
}

public abstract class DeviceType1 : DeviceBase
{
    public override void ReadMotorSpeed()
    {
        // Return motor speed of motor of dev1
    }
}

public abstract class DeviceType2 : DeviceBase
{
    public override void ReadMotorSpeed()
    {
        // Return motor speed of motor of dev2
    }
}

public abstract class TargetBase
{
    public virtual void UsePowerButton() { throw new NotImplementedException(); }
}

public sealed class Target<D> : TargetBase where D : DeviceBase
{
    private D _device;
    public Target(D device) => _device = device;
    public override void UsePowerButton()
    {
        _device.UsePowerButton();
    }
}

public sealed class TargetWithTests<D> : TargetBase where D : DeviceBase
{
    private D _device;
    public TargetWithTests(D device) => _device = device;
    public override void UsePowerButton()
    {
        _device.UsePowerButton();
    }
}

public sealed class Simulation<D> : TargetBase where D : DeviceBase
{
    private D _device;
    public Simulation(D device) => _device = device;
    public override void UsePowerButton()
    {
        _device.UsePowerButton();
    }
}
Related