c# – Design issues/questions regarding internal interfaces in assembly and abstract base class in a public constructor


For information, I have been redirected from Stack OverFlow: https://stackoverflow.com/questions/63888557/design-issues-questions-regarding-internal-interfaces-in-assembly-and-abstract-b?noredirect=1#comment112978234_63888557

I’m currently facing a design issue while coding an assembly. I think it will be easier to understand by using the following example.
This assembly defines several lights which all have a state that can be known from outside of the assembly:

public interface ILight
{
    bool State { get; }
}

The capacity to turn a light off or on is only allowed internally so that I define an internal interface as such:

internal interface IInternalLight : ILight
{
    void SwitchOn();
    void SwitchOff();
}

Finally, from an external perspective, the assembly consumer can instantiate and use the LightManager class to act on lights:

public class LightManager
{
    private List<IInternalLight> lights;

    public List<ILight> Lights
    {
        get { return lights.ConvertAll(x => (ILight) x); ; }
    }

    public LightManager(List<IInternalLight> lights)
    {
        this.lights = lights;
    }

    public void SwitchOn()
    {
        foreach (IInternalLight light in lights)
        {
            light.SwitchOn();
        }
    }

    public void SwitchOff()
    {
        foreach (IInternalLight light in lights)
        {
            light.SwitchOff();
        }
    }
}

Of course, in the above example, I obtain a compilation error because IInternalLight is internal and cannot be exposed in a public constructor.

My way to solve this consists in defining an abstract class called LightBase which implements the internal interface:

public abstract class LightBase : IInternalLight
{
    protected bool _state = false;

    public bool State
    {
        get { return _state; }
    }

    internal LightBase() { }

    void IInternalLight.SwitchOff()
    {
        _state = false;
    }

    void IInternalLight.SwitchOn()
    {
        _state = true;
    }
}

so that a licit constructor for LightManager can be:

public LightManager(List<LightBase> lights)
{
    this.lights = lights;
}

While it’s working, I’m a bit puzzled by the following points:

  • in first place, I thought my design would simply consists of a single interface containing the internal part and several concrete classes (SimpleLight, ComplexeLight, VeryComplexeLight, …). C# forbids that so that a second interface purely internal is required and then I end up with an abstract class as well. It looks rather “complex” for such a small case.
  • I don’t know if exposing an abstract base class in a public constructor is a good practice. Actually I expected to only expose interfaces for testing purposes (typically for injection dependency). I don’t think exposing a public class called Light for example suits better.

Thank you.