简体   繁体   中英

hiding property from derived class

Jon Skeet brought up this issue once in his videos (though didn't provide with an answer).

Let's say we have a Class named Person and the Person class has Name property

Then we have another class, Spy. Of course a Spy is a Person so we will derive from the Person class.

public class Person
{
    public string Name { get; set; }
}

public class Spy : Person
{

}

We don't want people to know the Spy's name so we'd want this to give a compilation error:

static void ReportSpy(Spy spy) {
  string name = spy.Name;
}

or either:

static void ReportSpy(Spy spy)
{
   Person spyAsPerson = spy;
   string name = spyAsPerson.Name;
}

How could we prevent this kind of things from happening?

Make the Name property virtual in the base Person class. In derived Spy class, override the property and throw Exception in getter.

public class Person
{
    public virtual string Name { get; set; }
}

public class Spy : Person
{
    public override string Name
    {
        get
        {
            throw new Exception("You never ask for a spy's name!");
        }
        set
        {
            base.Name = value;
        }
    }
}

But, rather than throwing exception, I'd suggest something like

get
{
    return "**********";
}

Because, it breaks LSP (mentioned in another answer). What that means here (just an example) is, I can always do like

Person x = new Spy();

and pass it to some other method, which might be like

void RegisterForNextBallGame(Person p)
{
    playerList.Add(p.Name);
}

This method being unaware of the some spy roaming around the stadium, crashes while doing a simple honest duty!

Edit

Just to make it clear, this name=********** is still not a right solution . It will just save from the exceptions! Later, one might find lot of Persons walking down the code with name ********** which will cause later surprises and other issues.

A better solution would be a better design. Check Nathan's answer to get some hint.

If part of being a person is disclosing your name: Spy's aren't people

Having Spy inherit from person breaks the Liskov substitution principle : An object may be replaced with its subtype.

If Spys don't disclose their name they shouldn't be People in the context of your design. Perhaps you could design it differently:

public interface IPerson
{
    void EatLunch();
}

public interface INameDisclosingPerson : IPerson
{
    string Name {get; set; }
}

public interface ISpy : IPerson
{
    void DrinkCocktail();
    Package MakeDrop();
}

An example of this poor design in the real world is NetworkStream . It implements the Position property by throwing a NotSupportedException. So code you write for a Stream may break at runtime for the NetworkStream . I'm also not a fan of this. A piece of design guidance: wrong things should break at compilation time and objects that inherit from interfaces they can't implement are terrible.

You can hide base class method or property with new keyword:

public class Person
{
    public string Name { get; set; }
}

public class Spy : Person
{
    public new string Name
    {
        get { throw new InvalidOperationException(); }
    }
}

It will not give you compilation errors, and you will still be able to access the base class Name property if you cast.

If you can modify the base class, change the property to virtual. Then you can override it in the derived and class and throw exception even with polymorphic calls.

All this will work at runtime, nothing you can do about it at compile time.

And as others mentioned in their answers, such design breaks Liskov substitution principle and should be avoided.

You can't. As already mentioned you could throw an Exception when accessing Spy's Name property but this would still compile. And, also already mentioned, this would break Liskov substitution principle and, I'd like to add, the open-closed principle as well.

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