DevinB
DevinB

Reputation: 8316

Preventing methods from being inherited

I have a base class Foo that is concrete and contains 30 methods which are relevant to its subclasses.

Now I've come across a situation that is specific only to the base class,and I want to create a method that cannot be inherited, is this possible?

Class Foo 
{
   /* ... inheritable methods ... */

   /* non-inheritable method */
   public bool FooSpecificMethod()
   { 
      return true;
   } 
}

Class Bar : Foo
{
    /* Bar specific methods */
}

var bar = new Bar();
bar.FooSpecificMethod(); /* is there any way to get this to throw compiler error */

EDIT

I'm not sure if I was clear originally.

I do understand the principles of inheritance, and I understand the Liskov substitution principle. In this case there is a single exception that ONLY deals with the 'un-inherited' case, and so I did not want to create an 'uninheritedFoo' subclass.

I was asking if it is technically possible to create a situation where foo.FooSpecificMethod() is a valid and publicly accessible method, but subclassoffoo.FooSpecificMethod() throws a compiler error.

Essentially I want a sealed method on an unsealed class.

Upvotes: 6

Views: 12270

Answers (11)

Evolution Rich
Evolution Rich

Reputation: 56

I have been trying to achieve this myself and came across this post which has some great answers without achieving what the poster was after, but there is a way to enforce this. You need to override the existing method and then use the Obsolete attribute. Setting the Obsolete attribute's error property to true will prevent compile.

Class Foo 
{
   /* ... inheritable methods ... */

   /* non-inheritable method */
   public bool FooSpecificMethod()
   { 
      return true;
   } 
}

Class Bar : Foo
{
    /* Bar specific methods */

   [Obsolete("Don't use this for whatever reason", true)]//true triggers the compiler error
   public new bool FooSpecificMethod()
   { 
      return true;
   } 
}

var bar = new Bar();
bar.FooSpecificMethod(); /* this now throws a compiler error */

Upvotes: 1

Daniel Hadad
Daniel Hadad

Reputation: 91

Perhaps you could simply create it as a virtual method on the parent class and then override it, throwing a NotImplementedException or something similar, on the child class that inherited it.

Also, but only if you're willing to put up with some spaghetti, you could put the method's signature in an interface and then have all the classes that'll require such method implement it. The downside is you'll have to declare the same method in all those children.

I'm not sure if it's even possible, but maybe an extension method could be written for that interface?

Keep in mind that these are all violations of OOP's encapsulation principle, albeit minor, which makes them all the more fun.

Upvotes: 0

Damian Vogel
Damian Vogel

Reputation: 1192

As others have pointed out, this is not possible, and most importantly, it shouldn't be necessary.

I came across the same problem when I had the following structure:
- A parent class with properties of child classes.
- The child classes would expose different properties, but all had the same initialisation procedure, so I put the code in the parent class.

public class Parent
{
    public CHILD1 Child1;
    public CHILD2 Child2;

    public Parent(params args){
        Child1 = new CHILD1(arg1, arg2);
        Child2 = new CHILD2(arg1, arg2);
    }
    //split here
    public Parent(object arg1, object arg2) {
        PropertyInfo[] list = this.GetType().GetProperties();
        foreach (var pi in list) {
            pi.SetValue(this, BL.Method(arg1, arg2, this.GetType().Name, pi.Name) // get data
        }
    }
}

public class CHILD1 : Parent
{
    public CHILD1(object arg1, object arg2) : base(arg1, arg2) { }

    public object C1Property1 { get; set; }
    public object C1Property2 { get; set; }
    // ..
}

public class CHILD2 : Parent
{
    public CHILD2(object arg1, object arg2) : base(arg1, arg2) { }

    public object C2Property1 { get; set; }
    public object C2Property2 { get; set; }
    // ..
}

Now I could call parent.Child1.C1Property1. But the code would also allow a call of the following: parent.Child1.Child1.Property1, which wouldn't make sense and result in an exception because the Child1.Child1 property would always be null.

In order to fix this, all I had to do was split the code of the parent class into two classes:

  • One holding the Child properties and calling child constructors
  • and one with the constructor logic to fill the properties.

Upvotes: 0

tpdi
tpdi

Reputation: 35171

Brian's right about Liskov Substitution (upmodded). And Reed's right about "is-a" (also upmodded); in fact they're both telling you the same thing.

Your public methods are a contract with users of your class Foo, saying that, "you can always" call those methods on Foo.

Subclassing Foo means that you're saying that a Subclass, e.g. Bar, is always acceptable to use where a Foo could be used. In particular, it means you inherit not (necessarily) Foo's implementation (you can override that, or Foo may be abstract and give no particular implementation for a method).

Inheritance of implementation (if any) is a detail; what you're really inheriting is the public interface, the contract, the promise to users that a Bar can be used like a Foo.

Indeed, they may never even know they have a Bar, not a Foo: if I make a FooFactory, and I write its Foo* getAFoo() to return a pointer to a Bar, they may never know, and sholdn't have to.

When you break that contract, you break Object Orientation. (And the Java Collection classes, by throwing NotSupported exceptions, entirely break OO -- users can no longer use so-called subclasses polymorphically. That's poor, poor design, which has caused major headaches for many many Java users, not something to emulate.)

If there's a public method that Foo subclasses can't use, then that method shouldn't be in Foo, it should be in a Foo subclass, and the other subclasses should derive from Foo.

Now, that does NOT mean that all methods in Foo should be callable on subclasses. No, I'm not contradicting myself. Non-public methods are not part of a class's public interface.

If you want a method in Foo that can't be called on Bar, and shouldn't be publicly callable in Foo, then make that method private or protected.

Upvotes: 6

Denis
Denis

Reputation: 12087

You should consider Composition [http://en.wikipedia.org/wiki/Composite_pattern} over inheritance if you want to achieve what you are trying to do and expose methods from the private object (i.e. the one you are currently inheriting from).

Upvotes: 0

supercat
supercat

Reputation: 81217

There are two reasons a derived class may hide base-class members without violating the Liskov Substitution Principle:

  1. If the member in question is `protected`, it essentially represents a contract only between the parent class and the derived class. As such, it does not impose any obligations on the derived class, except as required by the contract with the parent. If public members of the base class relies upon some non-public particular member of outside instances having some particular meaning, a derived class which changes the meaning of that member could violate LSP even though the member itself is not public, since changing its meaning could alter the behavior of the public members which use it. In cases where a base class defines a protected member but does not use it, however, a derived class could do anything it likes with that member without violating LSP. A key thing to understand with protected members is that the reason a `ToyotaCar` should not alter the semantics of public members of `Car` is that a reference to a `ToyotaCar` might be given to code which is expecting a `Car` rather than a `ToyotaCar`. On the other hand, if `ToyotaCar` alters the behavior of a protected method of `Car` in a fashion which isn't exposed by any public members, the only code which could notice such alteration is code which is within either `ToyotaCar` or a derivative thereof, and such code is going to know that it has a `ToyotaCar`. Code which is in some other `Car` derivative (e.g. a `FordCar`) can access the protected members of `Car`, but is guaranteed *not* to access those methods on an instance of `ToyotaCar`.
  2. Sometimes it is useful to have a base type or interface expose a number of members which will not all be applicable to every implementing type. While the Interface Segregation Principle would suggest that one should avoid "kitchen-sink" interfaces, there are cases where such interfaces may be more practical than any alternative. For example, some kinds of a "stream" class might support different handshake modes, but other types would not. If references streams will be passed through code that won't care about handshaking, it may be easier to have a Stream class include a handshake-selection property which may or may not be usable, than to require code to try casting a passed-in reference to `IHandshakeSelector` and set `IHandshakeSelector.HandshakeMode` if so. On the other hand, if a particular stream class would behave identically for all handshake modes except `XonXoff`, which would throw an exception if code tries to set that, it may make sense for that class to hide the `HandshakeMode` property.

I would posit that while base-class member hiding is often a sign of bad design, there are cases where hiding base-class members would be more appropriate than leaving them exposed; if a derived class cannot possibly use a protected method correctly (as would be the case with the MemberwiseClone method available to derivatives of List<T>) there's no reason to have it exposed. Unfortunately, there's no completely clean way of hiding such members. The best one can do is declare a public member of the same name (using a "new" modifier) which would block off all access to the base-class member. For example, code could define a nested public static class named MemberwiseClone with no members. The EditorBrowseable attribute could be used to prevent Intellisense from showing that nested class, but even if code did try to use that class, it has no members, and one cannot create a storage location of that type, so it should be pretty harmless.

Upvotes: 0

DevinB
DevinB

Reputation: 8316

The solution I ended up using was creating a public inner inherited class. That way it is able to access the private variables of the baseclass (as it needs to) and I don't need to expose publicly any of those private variables or functions (which I don't want to).

Thanks so much for all your advice, it caused me to rethink exactly what I needed from this arrangement.

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564631

I would rethink the need for this.

If you are using inheritance, you are suggesting that "Bar" IS A "Foo". If "Bar" is always a "Foo", methods that work on "Foo" should also work on "Bar".

If this isn't the case, I would rework this as a private method. Publically, Bar should always be a Foo.


Just to take this one step further -

If you could do this, things would get very complicated. You could have situations where:

Foo myBar = new Bar(); // This is legal
myBar.FooSpecificMethod(); // What should this do?  
                           // It's declared a Foo, but is acutally a Bar

You can actually force this behavior using reflection, though. I think it's a bad idea, but FooSpecificMethod() could check the type of this, and if it isn't typeof(Foo), throw an exception. This would be very confusing, and have a very bad smell.


Edit in response to question's edit:

There is no way for the compiler to enforce what you are asking. If you really want to force the compiler to check this, and prevent this, you really should consider making Foo a sealed class. You could use other extension methods than subclassing in this case.

For example, you might want to consider using events or delegates to extend the behavior instead of allowing the object to be subclasses.

Trying to do what you are accomplishing is basically trying to prevent the main goals of inheritance.

Upvotes: 11

Jason Coyne
Jason Coyne

Reputation: 6636

Making the function private will prevent it from being called by the subclasses directly.

If you are talking about virtual functions that you do not want to be overloaded, marking the function as sealed at the point that you want to "lock" the function works.

Even if it is a private function, it could still be called by reflection.

You could also declare the function on an interface, and explicitly implement the interface on the class, which would force you to cast it to the interface to use the function.

Upvotes: 2

Kibbee
Kibbee

Reputation: 66132

You could make a private function, and then call it using reflection. Probably a little overboard. Anyway, just put the function in your base class, along with comments saying it should only be called from the base class. Maybe even those nice /// comments that show up with intellisense. Then, you might get a bug, but then well, you'll always get bugs, and the best you can do is document this situation to try and avoid it.

Upvotes: 1

Brian
Brian

Reputation: 118895

No, this would violate the Liskov substitution principle.

Pragmatically, you can either have it "throw NotImplementedException()" in Bar, or remove the method from Foo and move it down to the subclasses to which it applies.

Upvotes: 4

Related Questions