Search code examples
c#classinheritanceencapsulation

Change return type to derived type during override


I would like to have interace A. Which will allow objects of type A generate other objects of type A. I need the same behavior for type B. In my application is true that all B are also A. So I would like B to be derived from A.

This is my try:

public interface A {
    A method1();
}
public interface B : A {
    overrride B method1();
    void otherMethod();
}

Note that override keyword dosn't compile here. The only way to make the project compile is make the interface B look as follows:

public interface B : A {
    //A method1(); /* commented out because it is inherired */
    void otherMethod();
}

However I would like to promise by interface B, that objects of this type have method to produce other objects of type B.

Implementation of interface B could look like:

class Foo : B {
    B metod1();
}

Where I want B metod1() to be implemantation of B method1() from interface B and I also want the same method to be implementation of A method1() from interface A. I expect the same behavior in all classes implementing interface B. So I don't want to implement method1 each time twice for both interfaces.

I am doing this in c# with interfaces. But I believe that similar question could be interesting even with classes and possibly also in Java.


Solution

  • The only way to do this properly is using generics like this:

    public interface A<T> where T : A<T>
    {
        T method1();
    }
    

    Then B looks like this:

    public interface B : A<B>
    {
        void otherMethod();
    }
    

    And finally, implementing a class would go like this:

    public class Bravo : B
    {
        public B method1() { return null; }
        public void otherMethod() { }
    }
    

    However, you can use the new keyword to shadow a method in an interface, but this isn't a great idea as it makes it harder to reason about your code as it breaks normal inheritance.

    Try this:

    public interface A
    {
        A method1();
    }
    
    public interface B : A
    {
        new B method1();
        void otherMethod();
    }
    
    public class Bravo : B
    {
        A A.method1()  { return null; }
        public B method1() { return null; }
        public void otherMethod() { }
    }