4

Is it possible to implement an interface in a base class and allow calling/overriding the implemented method in the first derived class level but prevent calling it from any further derived classes?

    public interface IInterfaceSample
    {
        bool Test();
    }

    public class Base: IInterfaceSample
    {
        public virtual bool Test()
        {
             return True;
        }
    }

    public class Sub1: Base
    {
        //I need to be able to override the Test method here
        public override bool Test()
        {
             return True;
        }
    }

    //Under a separate project:
    public class Sub2: Sub1
    {
       //I need to prevent overriding the interface implementation in this class
    }

Now what i need is this:

    var b = new Base();
    b.Test();//This should work

    var s1 = new Sub1();
    s1.Test();//I need this to work too

    var s2 = new Sub2();
    s2.Test();//I need to prevent doing this

So far from research i think this might not be possible because interfaces has to be public, otherwise there is no real value of using them.

In my case, i need class Sub2 to have access to the properties in Sub1 but only that and no access to the methods on that class and specially the interface implementation methods.

The only way i was able to do this was to not use the interfaces at all and do it like this:

    public class Base
    {
        internal virtual bool Test()
        {
             return True;
        }
    }

    public class Sub1: Base
    {
        //I am able to override the Test method here
        internal override bool Test()
        {
             return True;
        }
    }

    //Under a separate project:
    public class Sub2: Sub1
    {
       //Nothing to override here which is what i need
    }

    var b = new Base();
    b.Test();//This works

    var s1 = new Sub1();
    s1.Test();//This works too

    var s2 = new Sub2();
    s2.Test();//This is prevented

However i am wondering if this is still available to achieve with interfaces, any help is much appreciated.

Anas
  • 61
  • 1
  • 4
  • If Sub1 inherits the interface then Sub2 doesn't needd to inherit any members of the interface as they're already inherited through Sub1. You can make the interface internal by the way. – Bauss Mar 19 '15 at 10:49
  • It looks to me like you need to redesign your object model, if a subclass shouldn't have some of the functionality of the parent class then should it be a child? what would happen if you passed an instance of `Sub2` to a method which could accept any instance of `Base`? – Trevor Pilley Mar 19 '15 at 10:54
  • I just tried this, however Sub2 can still override implementation of the Test method and also the Test method can be called from a Sub2 class instance and i need to prevent both of these. – Anas Mar 19 '15 at 10:55
  • Good point @TrevorPilley, however, in my case the only purpose of creating Sub2 as a child of Sub1 is sharing the structure of properties without sharing other functionality and methods, Sub1 and Sub2 will be used in two separate and different ends of the project and non of them will be accessible in the wrong place, i only need to prevent duplicating Sub 1 in another place with just removing the methods from it to achieve my goal. – Anas Mar 19 '15 at 10:59

3 Answers3

3

No, this isn't possible - it would break the whole point of polymorphism. In particular, imagine you didn't use var, but used the types explicitly:

Sub1 s2 = new Sub2();
s2.Test();

That has to compile:

  • The first line has to compile because Sub2 is derived from Sub1.
  • The second line has to compile because you wanted s1.Test() to compile, where the compile-time type of s1 is Sub1 as well.

As a rule of thumb, if you have two classes X and Y, and only some of the public operations on X are valid for Y, then Y shouldn't derive from X. You should be able to treat any instance of a derived class as if it's an instance of the base class (and all interfaces it implements).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you @Jon, i see your point and it makes sense, the whole purpose of what i am trying to do is to prevent duplicating the properties structure and having to maintain that over and over again, i could easily just create a duplicate class with only the properties and use it, but this will cause much headache later, so i was wondering if there is a way i could do this with inheritance but prevent the methods from being used. – Anas Mar 19 '15 at 11:07
  • @Anas: I don't quite understand your comment, to be honest about "duplicating the properties structure" - but it does feel like you should probably be using composition rather than inheritance for this... – Jon Skeet Mar 19 '15 at 11:14
  • sorry if i am not clear enough, i need to have a class with list of properties in two separate layers of the project, Like public class Class1 { public string P1 {get;set;} public string P2 {get;set;} public string P3 {get;set;} } But this class has some functionality that should be available in one layer but not the other, so i don't want to end up duplicating the class in both ends with minor differences since it will add the overhead of maintaining both of them to keep then in sync whenever we change a property or something, it will be great if i can do this with inheritance. – Anas Mar 19 '15 at 11:25
  • 1
    @Anas: It sounds like you should extract the common functionality into a separate type - then you can use composition to make Class1 have a CommonProperties reference, and ditto for your other class. Inheritance is *not* appropriate here. – Jon Skeet Mar 19 '15 at 11:26
  • Thank you @Jon, regarding inheritance, you mentioned that it is not appropriate, is it just for the fact that you can turn around it by using types explicitly or are there any other disadvantages that you have in mind? – Anas Mar 19 '15 at 11:54
  • @Anas: It's "just" the fact that you're breaking the assumption of inheritance: that it's appropriate to use any instance of a derived type as an instance of a base type. Something which deals with a reference of type `Base` or `Sub1` shouldn't need to worry about whether it's *actually* a `Sub2`. – Jon Skeet Mar 19 '15 at 11:56
1

You want the Test method to be available only in Sub1 but still share the same properties with Sub2. This can be achieved by changing the inheritance chain from this:
enter image description here
to this:
enter image description here

B0Andrew
  • 1,725
  • 13
  • 19
-1

Use sealed protected override bool Test() in Sub1

Radin Gospodinov
  • 2,313
  • 13
  • 14