views:

173

answers:

6

Consider the Employee, Manager, and Assistant classes:

public class Emp
{
    public string Name { get; set; }
    public Manager Manager { get; set; }
    public Assistant Assistant { get; set; }
}

public class Manager : Emp
{ 
}

public class Assistant : Emp
{
}

The goal is to DISALLOW a piece of code to access a property like this:

var foo = new Manager();
var elmo = new Emp();
elmo.Manager = foo;
elmo.Manager.Manager = new Manager(); 
//how to disallow access to Manager.Manager ?

Because Manager inherits from Emp, it has a .Manager and .Assistant property.

Question

Are there any modifiers in .NET's inheritance implementation to remove the .Manager and .Assistant properties?

Update

Thank you for your great answers, everyone. I was hoping the simplification and contrivance of Emp/Mgr would show through in this question. It's clear that the inheritance, in this example, should be taken to another commonality (something like Person, where the classes would share names, birthdates, etc.) Your input is much appreciated!

+2  A: 

No, there isn't.

You can make the base class property virtual, then override it to throw an exception in the setter, but there's no way to give a compile-time error. After all, there is nothing you do at compile time to prevent

(elmo.Manager as Employee).Manager = new Manager();

However, you can write

public class ManagerEmployee : Emp {     
    public new ManagerEmployee Manager { 
        get { return base.Manager; }
    }
}

Note that this won't prevent casting.

SLaks
+4  A: 

No - because it would break Liskov's Subsitution Principle. Basically, you can add things, but you can't take them away.

You could potentially override the property to throw an exception at execution time, but you can't do it at compile time.

Generally if you want to disallow this sort of thing, you should consider composition rather than inheritance, as you don't have a genuine inheritance relationship.

Jon Skeet
+6  A: 

Doing this would violate the Liskov substitution principle, and is usually a sign of a questionable design. In general, any subclass should be able to be used in any context that a base class would be. If Managers don't have .Managers, then they aren't Emps, and shouldn't inherit from them.

recursive
A: 

As others have said. No. I'll add that if not every employee has a manager and an assistant, then your inheritance hierarchy is wrong. It would seem that the only thing an employee and manager share is a name. You can add via inheritance, but you cannot take away via inheritance.

Daniel Auger
A: 

No you can't do this, and you wouldn't want to - either Manager is an Employee and has a Manager and an Assistant, or it doesn't and hence should have a different base class i.e. this situation indicates a design flaw. One possibility could be to return null for these properties though if that makes sense for the domain.

Lee
A: 

Like most things, it depends. Given the following classes:

public class foo
{
    public string Test { get { return "foo"; } } 
}

public class bar : foo
{
    public new string Test { get { return "bar"; } }
}

And the following code:

        bar a = new bar();
        // returns bar
        literalTest1.Text = a.Test;

        foo b = new foo();
        // returns "foo"
        literalTest2.Text = b.Test;

        foo c = new bar();
        // returns "foo"
        literalTest3.Text = c.Test;

You can see, based on the comments above, that you can override a property that is not declared as virtual. However, the overridden property will only be used when the object variable is declared as the type that overrides the property - not as any of its ancestors. This effectively breaks polymorphism.

Fix your ancestor class instead.

David Lively