0

I have a class A which derives from class B:

public class B
{
   protected void Run() // pass data here used by all 3 Run methods
   {
     BeforeRun();
     RunInternal();
     AfterRun();
   }

   private void RunInternal()
   {

   }

   private void BeforeRun()
   {

   }

   private void AfterRun()
   {

   }
}

public class A : B
{

}

What is the nearest achievement I can get to force the user who inherits from class B MUST call the base method Run() ?

Add protected, virtual, abstract, etc... where you want, I am free to do changes where you suggest.

meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
Elisabeth
  • 20,496
  • 52
  • 200
  • 321
  • Do You want to create an api/framework? – icbytes Jul 31 '16 at 21:00
  • 1
    "Must" call it *when*? During object construction? At some undetermined point afterward? – David Jul 31 '16 at 21:00
  • make `Run()` public? – M.kazem Akhgary Jul 31 '16 at 21:01
  • 4
    When do you *want* them to call `Run`? I suspect you're looking for the template method, but you're already half way there - you just want to make `Run` public, then make `RunInternal` abstract protected. – Jon Skeet Jul 31 '16 at 21:01
  • @David As soon as I derive from class B I should be forced to call B.Run(). I can force the user with abstract key word, but then the Run() method can not have a body, but I need an implementation in the base class. – Elisabeth Jul 31 '16 at 21:06
  • @Elisabeth: `"As soon as I derive from class B"` - So... when the class is constructed? Can you just call `Run()` as the last operation in the constructor for `B`? Then derived classes don't even need to know or worry about it. (Though some operations might not be great for a constructor, it could depend on what `Run()` does.) – David Jul 31 '16 at 21:08
  • @David Yes when the class A is constructed, derives from class B, user is compiling and should get an error that certain base class with an implementation (Run method) is not called. – Elisabeth Jul 31 '16 at 21:10
  • 1
    @Elisabeth: I'm not following what you're describing there. If you want to call `Run()` in the constructor, then just call it in the constructor: `public B() { Run(); }` Derived classes will never even need to know about it. – David Jul 31 '16 at 21:12
  • @David Yes, but make the constructor of an abstract class `protected`. Maybe she just wants to change `protected void Run()` into `protected B()`. – Jeppe Stig Nielsen Jul 31 '16 at 21:57
  • You can't require someone to call a method except for the constructor. But a class's behavior shouldn't be in the constructor or called from the constructor. It should be in methods that are called after the class is constructed. – Scott Hannen Jul 31 '16 at 22:04
  • You cannot force this, *protected* does not mean it is protected from abuse or mis-use. Use *internal* instead so you don't have to look to far for the trouble-maker. And likewise a potential trouble-maker doesn't have to look too far for you. – Hans Passant Jul 31 '16 at 23:15
  • Are you trying to force the children of the class to call Run() of the base class while implementing some of their own methods? As far as I know, it is not possible. Consider looking at "Strategy" and "Template method" patterns. – Sergey.quixoticaxis.Ivanov Aug 01 '16 at 00:36

2 Answers2

6

You can't require someone to call a method, except for the constructor. But a class's behavior shouldn't be in the constructor or called from the constructor. A class shouldn't start doing something just because we instantiated it. It should do something when we call its methods.

When we design a class it typically has one or two methods which are the primary responsibility of that class. Whoever creates an instance of the class is going to call one or more of those methods because that's the only reason why the class exists.

Instead of adding another method and expecting others to call it, you design the class so that the primary methods cannot be overridden. The only public methods are in the base class. The methods that get overridden aren't public. That way the base class methods always get called, and if there's something you want the base class to always do, it always gets done.

That way other classes don't change the required base class behavior. They only extend it.

public abstract class TheBaseClass
{
    public void DoSomething()
    {
        AlwaysDoThis();
        InheritedClassBehavior();
    }

    private void AlwaysDoThis()
    {  
        //This method in the base class always gets called.
        //You don't need to explicitly require someone
        //to call it.
    }

    protected abstract void InheritedClassBehavior();   
}

public class TheInheritedClass : TheBaseClass
{
    protected override void InheritedClassBehavior()
    {
        //The inherited class has its own behavior here.
        //But this method can't be called directly because
        //it's protected. Someone still has to call
        //DoSomething() in the base class, so AlwaysDoThis()
        //is always called.
    }
}

InheritedClassBehavior is protected, so nothing can call it directly. The only way to call it is by calling DoSomething, which will always call the method in the base class, AlwaysDoThis().

InheritedClassBehavior is abstract, so inherited classes must implement it. Or you could make it virtual - it has an implementation in the base class but an inherited class can override it. (If there aren't any abstract methods then the base class doesn't need to be abstract. The base class would only be abstract if you want to prevent creating instances of the base class, only allowing creation of inherited classes.)

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
0

Your best option is to have a base implementation in A (so make it virtual), and only override it in the derived classes if they need to change the behavior of Run().

Anything that calls Run() will get the base implementation unless there has been an override supplied. There is no way you can force the override to call the base, classical OO simply doesn't work like that.

You should also be careful of calling a virtual method from a constructor - Resharper will warn you about this (because an override may get called, and this is unknown to the base implementation).

But other than that, there is no way within C# to force a derived class to call a particular method - a derived class extends the base class, so to force this sort of behavior would break basic OO concepts. Even if you put the calls into a constructor in the base class there is no guarantee that a derived class will invoke that constructor. You can force the base class to call the derived class (use an abstract base method, this must be implemented in the derived class), the derived method can then call back to a base method; but this in itself is a bit of a work around that is really a waste of time unless some of the derived classes are actually going to add some functionality to Run().

One other approach to consider is to use a product like PostSharp - it allows you to use attributes on methods to achieve a cross cutting pattern. This still doesn't force a derived class to call base implementations, but it may be a convenient way to achieve what you are wanting (cross cutting is used for auditing or logging patterns, where a specific method must be called when another method is invoked).

Community
  • 1
  • 1
slugster
  • 49,403
  • 14
  • 95
  • 145
  • That works if you're okay with allowing derived classes to "opt out" of calling the base implementation of `Run()`, but not if you want to require it. – Scott Hannen Jul 31 '16 at 22:12
  • @ScottHannen I just added another paragraph. This might be achievable with other languages, but it isn't possible with C# by itself. – slugster Jul 31 '16 at 22:18
  • Agreed - it's a matter of learning to work with the language, not against it. You can control what happens when someone calls a method but you can't make someone call a method (and you wouldn't want to.) – Scott Hannen Jul 31 '16 at 22:23