Search code examples
c#inheritancemultiple-inheritancefluent-interface

Fluent interfaces and multiple inheritance in C#


This question is similar to this one. The difference is that I'd like to have two base classes.

Example:

public class Circle
{
    private string _radius { get; set; }

    public Circle Radius(string radius)
    {
        _radius = radius;
        return this;
    }
}

public class Box
{
    private string _width { get; set; }

    public Circle Width(string width)
    {
        _width = width;
        return this;
    }
}

public class CircleAndBox : Circle, Box // Can't do in c#
{
    // should contain methods from both Circle and Box, but return CircleAndBox
}

Maybe Circle and Box was not the best example. Basically they represent classes with different properties and methods. Class CircleAndBox just happens to have the same properties and methods as both Circle and Box. CircleAndBox may have additional properties and methods that do not exist neither in Circle nor in Box.

Desired Result

I should be able to write:

var circle = new Circle().Radius("5");
var box = new Box().Width("6");
var circleAndBox = new CircleAndBox().Radius("5").Width("6");

It would be Super if:

When I add a method to Circle or Box class, I should not touch CircleAndBox class. Just like with regular inheritance from a single class, CircleAndBox should automatically inherit all public methods from both Circle and Box


Solution

  • Have CircleAndBox inherit from neither class, but rather reference objects of those classes. It will have to redefine the methods from each class. You can add implicit conversions to Circle and Box to allow it to be used in contexts where references to those objects are expected.

    public class CircleAndBox
    {
        public Circle Circle { get; private set; }
        public Box Box { get; private set; }
    
        public CircleAndBox()
        {
            Circle = new Circle();
            Box = new Box();
        }
    
        public CircleAndBox Radius(string radius)
        {
            Circle.Radius(radius);
            return this;
        }
    
        public CircleAndBox Width(string width)
        {
            Box.Width(width);
            return this;
        }
    
        public static implicit operator Circle(CircleAndBox self)
        {
            return self == null ? null : self.Circle;
        }
    
        public static implicit operator Box(CircleAndBox self)
        {
            return self == null ? null : self.Box;
        }
    }
    

    Note that the implicit conversions will not preserve the type of the object, so one should not use this technique to pass a CircleAndBox to a method taking a Box and expect the result on the other side to be a CircleAndBox.

    CircleAndBox cb = new CircleAndBox();
    
    // Implicit conversion, b contains a Box object.
    Box b = cb;
    
    // Compile-time error CS0030.
    cb = (CircleAndBox)b;