Hiding a property from a derived class

John Skeet raised this issue once in his videos (although he did not give an answer).

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

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

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

We don’t want people to know the name Spy, so we 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 can we prevent such things?

+6
source share
4 answers

Make the Name virtual property in the base class Person . In the Spy derived 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 name!"); } set { base.Name = value; } } } 

But instead of throwing an exception, I would suggest something like

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

Because it breaks the LSP (mentioned in another answer). What does this mean (just an example), I can always do as

 Person x = new Spy(); 

and pass it to another method that might look like

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

This method, unsuspecting that some kind of spy roaming the stadium, falls, performing a simple honest duty!

Edit

To make this clear, this name=********** is still not suitable. He will simply save you from exclusion! Later, you could find a lot of people who walked around the code with the name **********, which would cause subsequent surprises and other problems.

The best solution is the best design. Check Nathan's answer for a hint.

+6
source

If part of a person reveals your name: Spy is not people

Inheriting Spy from a person violates the Liskov Substitution Principle : an object can be replaced by its subtype.

If Spys do not reveal their name, they should not 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, raising a NotSupportedException. Therefore, the code you write for Stream may be corrupted at runtime for NetworkStream . I'm not a fan of this either. Part of the design guide: the wrong things should break at compile time, and objects that inherit from interfaces that they cannot implement are terrible.

+6
source

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

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

This will not give you compilation errors, and you can still access the property of the base class Name if you execute it.

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

All this will work at runtime; you cannot do anything at compile time.

And, as mentioned in their answers, such a design violates the Liskov principle of substitution and should be avoided.

+1
source

You can not. As already mentioned, you can throw an exception when accessing the Spy Name properties, but this will still compile. And, as already mentioned, this violates the principle of Liskov’s replacement and, I would like to add, the principle of open closure.

+1
source

All Articles