开发者

Force base method call

开发者 https://www.devze.com 2023-01-21 04:53 出处:网络
Is there a construct in Java or C# that forces inheriting classes to call the base implementation?You can call 开发者_如何学Gosuper() or base() but is it possible to have it throw a compile-time error

Is there a construct in Java or C# that forces inheriting classes to call the base implementation? You can call 开发者_如何学Gosuper() or base() but is it possible to have it throw a compile-time error if it isn't called? That would be very convenient..

--edit--

I am mainly curious about overriding methods.


There isn't and shouldn't be anything to do that.

The closest thing I can think of off hand if something like having this in the base class:

public virtual void BeforeFoo(){}

public void Foo()
{

this.BeforeFoo();
//do some stuff
this.AfterFoo();

}

public virtual void AfterFoo(){}

And allow the inheriting class override BeforeFoo and/or AfterFoo


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.


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() {
    }
}


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:

Force base method call


You may want to look at this (call super antipatern) http://en.wikipedia.org/wiki/Call_super


If I understand correctly you want to enforce that your base class behaviour is not overriden, but still be able to extend it, then I'd use the template method design pattern and in C# don't include the virtual keyword in the method definition.


No. It is not possible. If you have to have a function that does some pre or post action do something like this:

internal class Class1
{
   internal virtual void SomeFunc()
   {
      // no guarantee this code will run
   }


   internal void MakeSureICanDoSomething()
   {
      // do pre stuff I have to do

      ThisCodeMayNotRun();

      // do post stuff I have to do
   }

   internal virtual void ThisCodeMayNotRun()
   {
      // this code may or may not run depending on 
      // the derived class
   }
}


I didn't read ALL the replies here; however, I was considering the same question. After reviewing what I REALLY wanted to do, it seemed to me that if I want to FORCE the call to the base method that I should not have declared the base method virtual (override-able) in the first place.


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.


Don't think there's any feasible solution built-in. I'm sure there's separate code analysis tools that can do that, though.


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) {}

}


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
    }
}


I stumbled on to this post and didn't necessarily like any particular answer, so I figured I would provide my own ...

There is no way in C# to enforce that the base method is called. Therefore coding as such is considered an anti-pattern since a follow-up developer may not realize they must call the base method else the class will be in an incomplete or bad state.

However, I have found circumstances where this type of functionality is required and can be fulfilled accordingly. Usually the derived class needs a resource of the base class. In order to get the resource, which normally might be exposed via a property, it is instead exposed via a method. The derived class has no choice but to call the method to get the resource, therefore ensuring that the base class method is executed.

The next logical question one might ask is why not put it in the constructor instead? The reason is that it may be an order of operations issue. At the time the class is constructed, there may be some inputs still missing.

Does this get away from the question? Yes and no. Yes, it does force the derived class to call a particular base class method. No, it does not do this with the override keyword. Could this be helpful to an individual looking for an answer to this post, maybe.

I'm not preaching this as gospel, and if individuals see a downside to this approach, I would love to hear about it.


On the Android platform there is a Java annotation called 'CallSuper' that enforces the calling of the base method at compile time (although this check is quite basic). Probably the same type of mechanism can be easily implemented in Java in the same exact way. https://developer.android.com/reference/androidx/annotation/CallSuper

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号