Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call base method instead of override

In C#, class A contains a public method Foo() which does some processing and returns a value. protected method Bar(), also in class A performs the same logic as Foo(), followed by some additional processing, and then returns a value.

In order to avoid duplicating code, Bar() calls Foo() and uses the return as an intermediate value.

class A
{
  public virtual String Foo()
  {
     String computedValue;
     // Compute the value.
     return computedValue;
  }

  protected String Bar()
  {
     String computedValue;
     String intermediateValue = Foo();
     /// More processing to create computedValue from intermediateValue.
     return computedValue;
  }
}

Class B inherits from A and overrides Foo(). The override calls the base class implementation of Bar().

class B : A
{
   public override String Foo()
   {
     base.Bar();
   }
}

This (of course) goes into an infinite loop until the computer runs out of memory and then yields a stack overflow exception.

The most obvious solution is to rewrite A with a private FooInternals method which contains the guts of Foo. Foo and Bar are then modified to use the results of that method.

Is there a way to force A's Bar() to call A's Foo() instead of the override?

(I'm almost certainly being way too clever here; this goes completely against polymorphism. But I can't resist the urge to try pushing my knowledge a bit further.)

like image 931
ThatBlairGuy Avatar asked May 14 '13 16:05

ThatBlairGuy


1 Answers

Is there a way to force A's Bar() to call A's Foo() instead of the override?

Not directly. The simplest refactoring would be to change Foo to:

public virtual string Foo()
{
    return FooImpl();
}

private string FooImpl()
{
    String computedValue;
    // Compute the value.
    return computedValue;
}

Then change Bar to call FooImpl instead of Foo.

(This is probably what you meant in your "most obvious solution" paragraph - which I missed on the first reading, I'm afraid.)

Fundamentally this is just one of those areas where inheritance is problematic. When one virtual method calls another one, that needs to be documented so that subclasses can avoid causing problems - even though it feels like it should be an implementation detail. It's this sort of thing that makes me prefer composition over inheritance - where both are reasonable options, of course.

like image 152
Jon Skeet Avatar answered Oct 01 '22 22:10

Jon Skeet