Question

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

Was it helpful?

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;

OTHER TIPS

Inheritance means "is a".

Ball is a RoundThing. Circle is a RoundThing. Box is a SquareThing. Lamborghini is a Car, and Car is a Transport. Bus and Bicycle are also Transports.

If it isn't a "is a" relation, it is not inheritance. And in this is the explanation why multiple inheritance is not supported in C# and Java, and it is discouraged by most people I know in C++. An object is almost never two things at once.

Do not misuse inheritance simply to save code lines. Even if saving code lines was a legitimate goal (which I do not agree with), it is not even necessary. Two other constructs can help you here.

First, about the relation. What you are looking for is a totally different relation. Not "is a", but "can be used as". That is where interfaces come in. Interfaces specify what an object can be used as. So you could have two interfaces IBox and ICircle. Your CircleAndBox thing could then implement both interfaces, thus specify that it can be used as both.

Second, you can use one more relation to make life easier. You will not save code lines. But you will make sure that your CircleAndBox always has the proper behaviour, defined in the Circle and Box classes. For that, you can use aggregation, together with the delegation pattern. Aggregation is a relation that says "has a". So make your CircleAndBox class have a private Circle object and a private Box object, then implement the ICircle and IBox interfaces simply by calling the respective method/property/event on the respective private objects, and return what they return.

Presto, you have a class that has a (aggregation) Circle and Box instance to actually pass the work to, which exposes these by having the same methods (delegation), and which thus can be used as (interface) a Circle and as a Box.

Use interfaces:

IBox and ICircle

public interface IBox
{
    Circle Width(string width)
}

public interface ICircle
{
    Circle Radius(string radius)
}

public class Circle : ICircle
{
    private int _radius { get; set; }

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

public class Box : IBox
{
    private int _width { get; set; }

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

public class CircleAndBox : ICircle, IBox
{
    // should contain methods from both Circle and Box, but return CircleAndBox
}

I don't think you can do exactly what you are expecting since C# (and .Net in general) does not support multiple inheritance of classes. You can inherit from one class and implement an interface.

For instance:

interface iBox
{
  iBox Width(string width); //Assuming you want Box here and not Circle
}

Then you have Box

class Box : iBox ...

Now you can have

public class CircleAndBox : Circle, iBox
{
private Box _helper;
public iBox Width(string width) { _helper.Width(width); return this; }
}

This isn't exactly what you want, but it is about as close as C# allows I think. If you are willing to use weak types, there is also a delegation method for passing things to _helper without explicitly implementing each method. However, with direct delegation, you would not return your CircleAndBox object but the _helper object instead. I am not certain that would serve the purpose.

Also, this would not work if you don't control at least one of the classes you are looking to inherit.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top