Home > Back-end >  How to avoid the a "derived class can have only one base class" problem in C#?
How to avoid the a "derived class can have only one base class" problem in C#?

Time:10-25

i'm new to C#. I learned that a derived class can have only one base class. In my opinion this is a weakness of C#, but maybe I don't get it right. I'm looking for "the best" solution to get around this while respecting the DRY and clean code principles. Below I created an example where I finally derived from two classes to show the idea. There are two obvious solutions to this:

  1. Implement the members and methods of CColor twice into CColoredRectangle and CColoredTriangle. But this violates the DRY principle
  2. Implement the members and methods of CColor into CShape (or derive a CColoredShape class as base for the others). But then the CColor methods are available in CRectangle and CTriangle where they are not supposed to exist. This breaks with the clean code idea.

Interfaces won't do the job as they dont allow members. Is there any elegant solution to this? Thanks in advance.

public abstract class CShape
{
    private double x,y;
    protected CShape(double x, double y)
    {
        this.x = x;
        this.y = y;
    }
    public abstract double Area { get; }


    public class CRectangle : CShape
    {
        protected CRectangle(double x, double y) : base(x, y) { }
        public override double Area => x * y;
    }
    public class CTriangle : CShape
    {
        protected CTriangle(double x, double y) : base(x, y) { }
        public override double Area => x * y * 0.5;
    }
    public class CColor
    {
        public int R,G,B; //I need members here, so an interface won't work
        public void MixColorWith(int r,int g,int b) { /*Code....*/}
    }
    public class CColoredTriangle : CTriangle, CColor //compiler error CS1721
    {

    }
    public class CColoredRectangle : CTriangle, CColor //compiler error CS1721
    {

    }
}

CodePudding user response:

I learned that a derived class can have only one base class. In my opinion this is a weakness of C# [...]

Let's go over what things are correct, in your opinion, to be able to quantify the statement that this is a weakness of C#, again in your opinion.

You posit that a colored triangle is a color. That's what inheritance means, it's an "is-a" relationship. And while there exist some colors that aren't colored triangles, you posit that at least some colors are colored triangles. Are we on the same page here?

So here's my opinion: there doesn't exist a single color that's a colored triangle. There is no "is-a" relationship here at all. You might be able to make a case for the fact that colored triangles "have-a" color, in which case you would add a Color property to it, but nothing more.

So there you go, diamond (multiple) inheritance is not needed for your problem.

Edit: Also the other thing you posit, "I need members here, so an interface won't work", is just plain wrong, on both accounts. Interfaces can have both properties and methods in C#.

CodePudding user response:

Generally, most pundits say you should "Prefer composition over inheritance".

And in this case, that is almost certainly the right thing to do.

A CColoredTriangle isn't a CColor, it has a CColor, and therefore it should just be a property of it.

Given that you seem to also want to be able to refer to objects just by the fact that they have a CColor, irrespective of what they Shape they are, it makes sense to create an IHasColor interface

public abstract class CShape
{
    private double x,y;
    protected CShape(double x, double y)
    {
        this.x = x;
        this.y = y;
    }
    public abstract double Area { get; }


    public class CRectangle : CShape
    {
        protected CRectangle(double x, double y) : base(x, y) { }
        public override double Area => x * y;
    }
    public class CTriangle : CShape
    {
        protected CTriangle(double x, double y) : base(x, y) { }
        public override double Area => x * y * 0.5;
    }
    public class CColor
    {
        public int R,G,B;
        public void MixColorWith(int r,int g,int b) { /*Code....*/}
    }
    public interface IHasColor
    {
        CColor Color {get; set;}
    }
    public class CColoredTriangle : CTriangle, IHasColor
    {
        CColor Color {get; set;}
    }
    public class CColoredRectangle : CTriangle, IHasColor
    {
        CColor Color {get; set;}
    }
}
  • Related