简体   繁体   中英

Hide Public Properties of Base Class in Derived Class

I was wondering if we could hide public properties of Base Class in Derived Class .

I have following sample problem statement for calculating Area of different shapes -

abstract class Shape
{
    public abstract float Area();
}

class Circle : Shape
{
    private const float PI = 3.14f;

    public float Radius { get; set; }
    public float Diameter { get { return this.Radius * 2; } }

    public Circle() { }

    public Circle(float radius)
    {
        this.Radius = radius;
    }

    public override float Area()
    {
        return PI * this.Radius * this.Radius;
    }
}

class Triangle : Shape
{
    public float Base { get; set; }
    public float Height { get; set; }

    public Triangle() { }

    public Triangle(float @base, float height)
    {
        this.Base = @base;
        this.Height = height;
    }

    public override float Area()
    {
        return 0.5f * this.Base * this.Height;
    }
}

class Rectangle : Shape
{
    public float Height { get; set; }
    public float Width { get; set; }

    public Rectangle() { }

    public Rectangle(float height, float width)
    {
        this.Height = height;
        this.Width = width;
    }

    public override float Area()
    {
        return Height * Width;
    }
}

class Square : Rectangle
{
    public float _side;

    public float Side
    {
        get { return _side; }
        private set
        {
            _side = value;
            this.Height = value;
            this.Width = value;
        }
    }

    // These properties are no more required
    // so, trying to hide them using new keyword
    private new float Height { get; set; }
    private new float Width { get; set; }

    public Square() : base() { }

    public Square(float side)
        : base(side, side)
    {
        this.Side = side;
    }
}

Now interesting part is here that in Square class Height & Width properties are no more required (as it is replaced by Side property) to expose to outer wold so I am using new keyword to hide them. But it is not working and user now can set Height and Width -

class Program
{
    static void Main(string[] args)
    {
        Shape s = null;

        // Height & Width properties are still accessible :(
        s = new Square() { Width = 1.5f, Height = 2.5f };

        Console.WriteLine("Area of shape {0}", s.Area());
    }
}

Does anyone know in C# is it possible to hide properties of derived class which are not required?

Important Note: One might point out that Shape -> Rectangle -> Square is not a suitable design of inheritance. But I would like to keep it that way because I do not want to write "not exact" but similar code again in Square class (note: Square class makes use of Area method of its base class Rectangle . In real world, in case of such type of inheritance that method logic may be more complicated)

Any sub-type is still fundamentally capable of being treated an instances of the base-type. You certainly can't hide the members if someone has a variable typed as the base-type . The most you can do would be to make them really annoying to use when using the derived type , for example:

[Obsolete, Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public new float Width { get { return base.Width;} }

You could also do something similar with override , and possibly even throw if the accessors (the set in particular) are used inappropriately.

However, it sounds more like you should be changing the inheritance model such that you never want to try to remove members.

I still think that Shape -> Rectangle -> Square is the source of all problems. Inheritance is not just about code reuse. If you have similar code to compute area, you can compose the logic: ie externalize the logic of area computation to a separate class, and reuse that in Square and Rectangle.

Coming back to your original question, the fact that you need to hide properties in the base class from the child classes is a big design smell - and the language designers would most definitely not have wanted such a feature.

(You may also want to read about Liskov Substitution Principle )

At first thought, I think I would declare Rectangle 's Height and Width as virtual and override it in the Square class, instead of trying to hide them :

class Square : Rectangle
{    
    public float Side{get;set;}

    public override float Height { get{return Side;}; set{Side =value;} }
    public override float Width {get{return Side;}; set{Side =value;} }

    public Square() : base() { }

    public Square(float side)
    {
        this.Side = side;
    }
}

What is an advantage of Square inheritance from Rectangle ? Maybe you need a new class like:

abstract class Square<TFigure> where TFigure : Shape
{
  public float Side {set; get;}

  protected Square(TFigure stereotype)
  {
     Side = GetStereotypeSide(stereotype) 
  }

  public abstract float GetStereotypeSide(TFigure stereotype);
}

then your square can look like following

class RectangleSquare: Square<Rectangle>
{
  public RectangleSquare() : base (new Rectangle(){Height = 1, Width = 2})
  {
  }

  public override float GetStereotypeSide(Rectangle stereotype)
  {
     return stereotype.Height*stereotype.Width;
  }
}

in case you still need a common object for Square and Shape than you can define

interface IGeometry{
}

and then add the interface inheritance to both classes

    class Shape : IGeometry
  ....

and

abstract class Square<TFigure> : IGeometry where TFigure : Shape

I echo @aquaraga. If you desire to hide what's public in a base class then derivation is not right. Composition is a better solution, delegating to the the other (base) class when necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM