74

If i have the following code example:

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA : ClassBase
{
    public int JustNumber { get; set; }

    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

What should I do to hide the property Name (Don't shown as a member of ClassA members) without modifying ClassBase ?

mmmmmm
  • 32,227
  • 27
  • 88
  • 117
Ahmed Magdy
  • 5,956
  • 8
  • 43
  • 75
  • 1
    This is a violation of one of the basic tenets of OOP (polymorphism and, relatedly, the `L` in SOLID). – jason Dec 09 '09 at 17:43
  • 2
    Specifically a violation of the liskov substitution principle (http://en.wikipedia.org/wiki/Liskov_substitution_principle) – Robert Venables Dec 09 '09 at 17:51
  • 45
    Many of the answers ignore the simple fact that a the base class may be provided by a third party. As this code is not owned, it cannot be changed. There is definite validity to wanting to create a more narrowly focused version of the base class by hiding members. And it is nicer to inherit than to use the base control as a component of a new control as that requires a lot of extra work in exposing methods already found on the base. – Mario Aug 12 '14 at 19:15
  • 3
    @Mario, if it that is the case, I strongly suggest to create your own class implementation and use an object to object mapper to set the properties you want. That way you create your more narrowly version of the third party classe. – digaomatias Jul 07 '15 at 20:32
  • To ask a question that summarizes differences in answers below, "hide the property" from *what*? – Sean Apr 20 '23 at 20:51

10 Answers10

91

I smell a code smell here. It is my opinion that you should only inherit a base class if you're implementing all of the functionality of that base class. What you're doing doesn't really represent object oriented principles properly. Thus, if you want to inherit from your base, you should be implementing Name, otherwise you've got your inheritance the wrong way around. Your class A should be your base class and your current base class should inherit from A if that's what you want, not the other way around.

However, not to stray too far from the direct question. If you did want to flout "the rules" and want to continue on the path you've chosen - here's how you can go about it:

The convention is to implement the property but throw a NotImplementedException when that property is called - although, I don't like that either. But that's my personal opinion and it doesn't change the fact that this convention still stands.

If you're attempting to obsolete the property (and it's declared in the base class as virtual), then you could either use the Obsolete attribute on it:

[Obsolete("This property has been deprecated and should no longer be used.", true)]
public override string Name 
{ 
    get 
    { 
        return base.Name; 
    }
    set
    {
        base.Name = value;
    }
}

(Edit: As Brian pointed out in the comments, the second parameter of the attribute will cause a compiler error if someone references the Name property, thus they won't be able to use it even though you've implemented it in derived class.)

Or as I mentioned use NotImplementedException:

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

However, if the property isn't declared as virtual, then you can use the new keyword to replace it:

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

You can still use the Obsolete attribute in the same manner as if the method was overridden, or you can throw the NotImplementedException, whichever you choose. I would probably use:

[Obsolete("Don't use this", true)]
public override string Name { get; set; }

or:

[Obsolete("Don't use this", true)]
public new string Name { get; set; }

Depending on whether or not it was declared as virtual in the base class.

David T. Macknet
  • 3,112
  • 3
  • 27
  • 36
BenAlabaster
  • 39,070
  • 21
  • 110
  • 151
  • 12
    The obsolete attribute also has a second parameter that specifies that using the property should be considered an error. At that point you should get a compile time error, which is helpful. – Brian Hasden Dec 09 '09 at 17:29
  • Thanks Brian, I should've thought to mention that, good catch. – BenAlabaster Dec 09 '09 at 17:32
  • I believe you can also use the "new" keyword to specify new functionality for the property even if it's not marked virtual. That would allow him to mark the property as obsolete even if it's from a class where the property wasn't virtual. – Brian Hasden Dec 09 '09 at 17:33
  • Yeah, you must've add that just as I was posting my comment. Oh well, just trying to help. – Brian Hasden Dec 09 '09 at 17:41
  • One should also mention that while the use of new will hide the original implementation of the property for the derived class, the original implementation will still be used when the object is cast to the base class, which can lead to nasty bugs – Grizzly Dec 09 '09 at 18:31
  • Very true. Obviously what the user who posted the question is trying to do is incorrect. I don't think there's any foolproof way to accomplish what he's trying to do. – Brian Hasden Dec 09 '09 at 19:03
  • @Grizzly - We did point out that it was a bad idea before we told the OP how to achieve it. That's one of the side effects. – BenAlabaster Dec 09 '09 at 19:07
  • Public methods of a base class should be implemented in derived classes per the LSP; protected properties have no such requirement (since the only way to access protected members is from the base object instance, which is always of the base type). What's the preferred way to hide protected members from sub-derived classes (e.g. to prevent a derived class from calling "MemberwiseClone")? – supercat Jul 17 '11 at 01:54
  • What I would give for Microsoft to provide the ability (via a new keyword, attribute or other means) to effectively hide unwanted members in derived classes. Then I could just use the `UserControl` class instead of doing so much work when I inherit the `Control` class. – Alex Essilfie Nov 26 '14 at 01:16
  • 2
    you have a text box. Except you want to subclass it so that it only accepts numbers, say. The .Text property (a string) is meaningless here. It might have some value, if it were an int or a double, but as a string, it is useless. Because the correct place for input-to-number conversions is *inside* the subclass. Are you suggesting that the control should not inherit from TextBox? That's an example of why you might want to do it. – PeteH Mar 17 '22 at 11:07
46

While technically the property won't be hidden, one way to strongly discourage its use is to put attributes on it like these:

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]

This is what System.Windows.Forms does for controls that have properties that don't fit. The Text property, for instance, is on Control, but it doesn't make sense on every class that inherits from Control. So in MonthCalendar, for instance, the Text property appears like this (per the online reference source):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • Browsable - whether the member shows up in the Properties window
  • EditorBrowsable - whether the member shows up in the Intellisense dropdown

EditorBrowsable(false) won't prevent you from typing the property, and if you use the property, your project will still compile. But since the property doesn't appear in Intellisense, it won't be as obvious that you can use it.

Ryan Lundy
  • 204,559
  • 37
  • 180
  • 211
36

Just hide it

 public class ClassBase
{
    public int ID { get; set; }
    public string Name { get; set; }
}
public class ClassA : ClassBase
{
    public int JustNumber { get; set; }
    private new string Name { get { return base.Name; } set { base.Name = value; } }
    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = 0;
    }
}

Note: Name will still be a public member of ClassBase, given the constraint of not changing the base class there is no way to stop that.

CCondron
  • 1,926
  • 17
  • 27
  • 5
    With this method, doing something like `ClassA.Name` outside `ClassA` will expose the `ClassBase.Name` property. It is not possible to `new` a member to a more restricted access than it was originally declared. – Alex Essilfie Nov 26 '14 at 01:05
  • 1
    That is the point of the note. Name will not be a public member of ClassA as per the question. For serialization and reflection this can be important. – CCondron Dec 02 '14 at 06:36
  • Yes, that's true. It is however worthy of note that when one wants to hide a member from an inherited class, it can be because he is setting the member's value to one of a set of predefined values and so changing it can result in unexpected behaviour. – Alex Essilfie Dec 02 '14 at 06:50
  • Agreed, and given the constraint of not changing the base class there is no way to stop that. – CCondron Dec 03 '14 at 16:13
  • Agreed. After all, when pushed, one can use reflection to modify even private members. – Alex Essilfie Dec 03 '14 at 16:17
  • 3
    Instead of all the rhetoric about why this shouldn't be done... THIS is the actual answer I was looking for. For serialization purposes I really needed this. This provide the solution I needed perfectly! Thanks very much! – SkyFighter Nov 02 '17 at 03:47
5

Why force inheritance when it's not necessary? I think the proper way of doing it is by doing has-a instead of a is-a.

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA
{
    private ClassBase _base;

    public int ID { get { return this._base.ID; } }

    public string JustNumber { get; set; }

    public ClassA()
    {
        this._base = new ClassBase();
        this._base.ID = 0;
        this._base.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}
flayn
  • 5,272
  • 4
  • 48
  • 69
5

I don’t think a lot of the people replying here understand inheritance at all. There is a need to inherit from a base class and hide its once public var’s and functions. Example, lets say you have a basic engine and you want to make a new engine that is supercharged. Well, 99% of the engine you will use but you will tweak a bit of its functionality to make it run much better and yet still there is some functionality that should only be shown to the modifications made, not the end user. Because we all know that every class MS puts out doesn’t really ever need any modifications.

Besides using the new to simply override the functionality it is one of the things that Microsoft in their infinite wis….. oh, I mean mistakes considered a tool not worthwhile anymore.

The best way to accomplish this now is multi-level inheritance.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

Class B does all your work and class C exposes what you need exposed.

Avshalom
  • 8,657
  • 1
  • 25
  • 43
engnrman
  • 91
  • 1
  • 3
  • In case anyone else stumbles upon this, I wanted to say that you are solidly correct. Assuming base classes aren't all written perfectly to work with every possible use of the base class, and assuming that we may want to use a base class that is very nearly perfect but not quite, a solution is required. Engine.GetManifoldVacuum() may no longer be pertinent and may no longer calculate correctly, so we want to hide it and add GetManifoldPressure(), or the like. Though I'm not sure how I feel about having an additional layer to create the needed obscurity. – omJohn8372 Aug 02 '23 at 17:17
2

You can't, that's the whole point of inheritance: the subclass must offer all methods and properties of the base class.

You could change the implementation to throw an exception when the property is called (if it were virtual)...

Fried Hoeben
  • 3,247
  • 16
  • 14
2

I completely agree that properties should not be removed from base classes, but sometimes a derived class might have a different more appropriate way to enter the values. In my case, for example, I am inheriting from ItemsControl. As we all know, ItemsControl has the ItemsSource property, but I want my control to merge data from 2 sources (for example, Person and Location). If I were to have the user enter the data using ItemsSource, I would need to separate and then recombine the values, so I created 2 properties to enter the data. But back to the original question, this leaves the ItemsSource, which I do not want the user to use because I am "replacing" it with my own properties. I like the Browsable and EditorBrowsable ideas, but it still does not prevent the user from using it. The basic point here is that inheritance should keep MOST of the properties, but when there is a large complex class (especially ones where you cannot modify the original code), rewriting everything would be very inefficient.

1

You can use Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
Abdus Salam Azad
  • 5,087
  • 46
  • 35
0

I think it is bad design if you have to do this, especially if you are able to design the code from the ground up.

Why?

Good design is to let the base-class share common properties that a certain concept has (virtual or real). Example: System.IO.Stream in C#.

Further down the lane bad design will increase the cost for maintenance and make implementation harder and harder. Avoid this as much as possible!

Basic rules which I use:

  • Minimize the number of properties and methods in the base-class. If you do not expect to use some properties or methods in a class that inherits the base class; do not put it in the baseclass then. If you are in the developmentstage of a project; always go back to the drawing-board now an then to check the design because things change! Redesign when needed. When your project is live the costs for changing things later in the design will go up!

    • If you are using a baseclass implemented by a 3:rd party, consider "go up" one level instead of "overriding" with "NotImplementedException" or such. If there is no other level, consider design the code from scratch.

    • Always consider to seal classes you do not want anyone to be able to inherit it. It forces coders to "go up one level" in the "inheritance- hierarchy" and thus "loose ends" like "NotImplementedException" can be avoided.

0

I know that the question is old, but what you can do is override the PostFilterProperties like this:

 protected override void PostFilterProperties(System.Collections.IDictionary properties)
    {
        properties.Remove("AccessibleDescription");
        properties.Remove("AccessibleName");
        properties.Remove("AccessibleRole");
        properties.Remove("BackgroundImage");
        properties.Remove("BackgroundImageLayout");
        properties.Remove("BorderStyle");
        properties.Remove("Cursor");
        properties.Remove("RightToLeft");
        properties.Remove("UseWaitCursor");
        properties.Remove("AllowDrop");
        properties.Remove("AutoValidate");
        properties.Remove("ContextMenuStrip");
        properties.Remove("Enabled");
        properties.Remove("ImeMode");
        //properties.Remove("TabIndex"); // Don't remove this one or the designer will break
        properties.Remove("TabStop");
        //properties.Remove("Visible");
        properties.Remove("ApplicationSettings");
        properties.Remove("DataBindings");
        properties.Remove("Tag");
        properties.Remove("GenerateMember");
        properties.Remove("Locked");
        //properties.Remove("Modifiers");
        properties.Remove("CausesValidation");
        properties.Remove("Anchor");
        properties.Remove("AutoSize");
        properties.Remove("AutoSizeMode");
        //properties.Remove("Location");
        properties.Remove("Dock");
        properties.Remove("Margin");
        properties.Remove("MaximumSize");
        properties.Remove("MinimumSize");
        properties.Remove("Padding");
        //properties.Remove("Size");
        properties.Remove("DockPadding");
        properties.Remove("AutoScrollMargin");
        properties.Remove("AutoScrollMinSize");
        properties.Remove("AutoScroll");
        properties.Remove("ForeColor");
        //properties.Remove("BackColor");
        properties.Remove("Text");
        //properties.Remove("Font");
    }
Nane
  • 318
  • 1
  • 8
  • 18
  • I think this code is specific to winforms or ASP maybe Xamarin forms. Mention it in your answer – Kira Feb 23 '17 at 12:31