Mark Gilbert's Blog

Science and technology, served light and fluffy.

Now you see it, now you… still see it? Hiding Inherited Properties

A while ago, a colleague of mine, Doug, and I got into a conversation about inherited properties, and the potential for hiding them.  The precise scenario we were looking at was a base class with a "public” property, and a child class that descends from it with the same property redefined as "private".  We weren’t sure if we could do this at all, and even if we could, was it a good idea?  We ended up going a different way for the problem we were working on, but the conversation stuck in my head and I decided that I would look into it more when I had the chance.

Let’s start by defining a very simple base class:

    public class BaseClass
    {
        public String StringProperty { get; set; }
    }

And then define a child class to descend from it:

    public class ChildClass : BaseClass
    {
    }

Now, we’ll add a new version of "StringProperty", and let’s begin by keeping the scope the same:

    public class ChildClass : BaseClass
    {
        public new String StringProperty { get; set; }
    }

Next, let’s have ChildClass initialize "StringProperty" with a value:

    public class ChildClass : BaseClass
    {
        public new String StringProperty { get; set; }

        
        public ChildClass()
        {
            this.StringProperty = "INITIALIZED By Child";
        }
    }

Now, let’s write a small program that instantiates ChildClass, and reassigns "StringProperty":

    class Program
    {
        static void Main(string[] args)
        {
            ChildClass MyChildClass = new ChildClass();

            Console.WriteLine("Initialized:\t{0}", MyChildClass.StringProperty);
            MyChildClass.StringProperty = "ASSIGNED By Program";
            Console.WriteLine("Assigned:\t{0}", MyChildClass.StringProperty);

            Console.ReadLine();
        }
    }

As soon as I compile this, I’ll get a warning:

‘ParentChildProperties.ChildClass.StringProperty’ hides inherited member ‘ParentChildProperties.BaseClass.StringProperty’. Use the new keyword if hiding was intended.

(Let me point out a little grammatical issue here.  When I read this, my first question, “Ok, what’s the new keyword I’m supposed to use?”  What they meant was that the keyword to use is literally “new”.  That should have been enclosed in quotation marks in the above message.")

A little research turns up a couple of MSDN articles talking about this warning, and the larger topic of "hiding" inherited properties:

  1. http://msdn.microsoft.com/en-us/library/aa691135(v=vs.71).aspx
  2. http://msdn.microsoft.com/en-us/library/vstudio/435f1dw2.aspx

Adding the "new" modifier sounds like it only suppresses the warning, and doesn’t actually change the behavior of the properties, but let’s test that, too.

Scenario 1 – Same scopes, no "new" modifier

When I run the application built so far, I get the following output:

Scenario 1

The property is initialized and assigned as I would expect it.  Furthermore, when I inspect the initialized version of the property in the Visual Studio debugger, I see that ChildClass.StringProperty has the initialized value, but BaseClass’s version is null.  When I inspect the assigned value, ChildClass.StringProperty now has the assigned value, and the BaseClass version is still "null".

Scenario 2 – Scope is narrowed, no "new" modifier

If I change ChildClass.StringProperty to be "private", thus narrowing the scope of the property, this is the output:

Scenario 2

When I inspect the initialized value, the ChildClass and BaseClass properties are exactly the same as they were in Scenario 1, but this time the initialized value doesn’t get printed.  Once I assign a new value to it, that assigned value is printed out.  However, when I inspect StringProperty, I find that the ChildClass version still has the initialized value, but BaseClass’s version now has the assigned value.

Scenario 3 – Same scopes, added the "new" modifier

When I add the "new" modifier to ChildClass.StringProperty, and change the scope back to "public", I get the exact same results as Scenario 1.  This seems to confirm that the “new” modifier doesn’t change behavior – it only suppresses a warning.

Scenario 4 – Scope is narrowed, added the "new" modifier

When I changed the scope to "private" again, I get the exact same results as Scenario 3.  Again, this seems to confirm that the “new” modifier doesn’t change behavior.

 

So what’s going on here?  I believe this line from the first MSDN article explains it:

A declaration of a new member hides an inherited member only within the scope of the new member.

In this case, the new member’s scope is ChildClass.  When I declare "StringProperty" to be private, and then tried to access it from the program (now outside the scope of ChildClass), it couldn’t find that version, so it fell back to using on the base class version.  Since that version is never assigned, the program can only print out the "null". 

How do we explain what we were seeing through the debugger?  The debugger has always been able to inspect the full properties of a class – regardless of their scopes – so that’s why it can show me the assigned values properly every time.  However, assigning MyChildClass.StringProperty, then, must actually assign the base class version of this property, and it’s the base class version that is printed – not ChildClass’s version.

As the second article describes, this is really not so much "hiding" as it is "replacing".  That sends me back to the original question.  Is there a way to truly hide a base class property, so that it doesn’t even show up in Intellisense?

Jon Skeet responded to this exact question on a forum post on Bytes.com in 2006.  In short, no, this is not allowed:

…However, you can’t hide them in terms of preventing people from calling them. Doing so would violate Liskov’s Substitution Principle – you should always be able to treat a derived type as the base type.

***

So, the technique of hiding a property I think will be related to my "use sparingly" bucket.

Furthermore, while narrowing the property’s scope in the child class is allowed by the language, it

  1. makes things harder to troubleshoot
  2. will downright mislead me when I’m inspecting properties in the debugger
  3. seems unfit for any real-world scenario

QED – Narrowing scope is bad and should be avoided.

Advertisements

October 18, 2013 - Posted by | Visual Studio/.NET

Sorry, the comment form is closed at this time.

%d bloggers like this: