Force base method call

后端 未结 13 1787
独厮守ぢ
独厮守ぢ 2020-12-11 00:15

Is there a construct in Java or C# that forces inheriting classes to call the base implementation? You can call super() or base() but is it possible to have it throw a comp

相关标签:
13条回答
  • 2020-12-11 00:33

    Not in Java. It might be possible in C#, but someone else will have to speak to that.

    If I understand correctly you want this:

    class A {
        public void foo() {
            // Do superclass stuff
        }
    }
    
    class B extends A {
        public void foo() {
            super.foo();
            // Do subclass stuff
        }
    }
    

    What you can do in Java to enforce usage of the superclass foo is something like:

    class A {
        public final void foo() {
            // Do stuff
            ...
            // Then delegate to subclass
            fooImpl();
        }
    
        protected abstract void fooImpl();
    }
    
    class B extends A {
        protected void fooImpl() {
            // Do subclass stuff
        }
    }
    

    It's ugly, but it achieves what you want. Otherwise you'll just have to be careful to make sure you call the superclass method.

    Maybe you could tinker with your design to fix the problem, rather than using a technical solution. It might not be possible but is probably worth thinking about.

    EDIT: Maybe I misunderstood the question. Are you talking about only constructors or methods in general? I assumed methods in general.

    0 讨论(0)
  • 2020-12-11 00:36

    EDIT Misread construct as constructor. Leaving up as CW since it fits a very limited subset of the problem.

    In C# you can force this behavior by defining a single constructor having at least one parameter in the base type. This removes the default constructor and forces derived types to explcitly call the specified base or they get a compilation error.

    class Parent {
      protected Parent(int id) {
      }
    }
    
    class Child : Parent { 
      // Does not compile
      public Child() {}
      // Also does not compile
      public Child(int id) { }
      // Compiles
      public Child() :base(42) {}
    
    }
    
    0 讨论(0)
  • 2020-12-11 00:38

    I use the following technique. Notice that the Hello() method is protected, so it can't be called from outside...

    public abstract class Animal
    {
        protected abstract void Hello();
    
        public void SayHello()
        {
            //Do some mandatory thing
            Console.WriteLine("something mandatory");
    
            Hello();
    
            Console.WriteLine();
        }
    }
    
    public class Dog : Animal
    {
        protected override void Hello()
        {
            Console.WriteLine("woof");
        }
    }
    
    public class Cat : Animal
    {
        protected override void Hello()
        {
            Console.WriteLine("meow");
        }
    }
    

    Example usage:

    static void Main(string[] args)
    {
        var animals = new List<Animal>()
        {
            new Cat(),
            new Dog(),
            new Dog(),
            new Dog()
        };
    
        animals.ForEach(animal => animal.SayHello());
        Console.ReadKey();
    }
    

    Which produces:

    0 讨论(0)
  • 2020-12-11 00:42

    The following example throws an InvalidOperationException when the base functionality is not inherited when overriding a method.

    This might be useful for scenarios where the method is invoked by some internal API.

    i.e. where Foo() is not designed to be invoked directly:

    public abstract class ExampleBase {
        private bool _baseInvoked;
    
        internal protected virtual void Foo() {
            _baseInvoked = true;
            // IMPORTANT: This must always be executed!
        }
    
        internal void InvokeFoo() {
            Foo();
            if (!_baseInvoked)
                throw new InvalidOperationException("Custom classes must invoke `base.Foo()` when method is overridden.");
        }
    }
    

    Works:

    public class ExampleA : ExampleBase {
        protected override void Foo() {
            base.Foo();
        }
    }
    

    Yells:

    public class ExampleB : ExampleBase {
        protected override void Foo() {
        }
    }
    
    0 讨论(0)
  • 2020-12-11 00:43

    Don't force a base call. Make the parent method do what you want, while calling an overridable (eg: abstract) protected method in its body.

    0 讨论(0)
  • 2020-12-11 00:45

    In java, the compiler can only enforce this in the case of Constructors.

    A constructor must be called all the way up the inheritance chain .. ie if Dog extends Animal extends Thing, the constructor for Dog must call a constructor for Animal must call a constructor for Thing.

    This is not the case for regular methods, where the programmer must explicitly call a super implementation if necessary.

    The only way to enforce some base implementation code to be run is to split override-able code into a separate method call:

    public class Super
    {
        public final void doIt()
        {
        // cannot be overridden
            doItSub();
        }
    
        protected void doItSub()
        {
         // override this
        }
    }
    
    public class Sub extends Super
    {
        protected void doItSub()
        {
         // override logic
        }
    }
    
    0 讨论(0)
提交回复
热议问题