C#: Any way to skip over one of the base calls in polymorphism?
Asked Answered
H

7

11
class GrandParent
{
    public virtual void Foo() { ... }
}

class Parent : GrandParent
{
    public override void Foo()
    {
       base.Foo();

       //Do additional work
    }
}

class Child : Parent
{
    public override void Foo()
    {
        //How to skip Parent.Foo and just get to the GrandParent.Foo base?

        //Do additional work
    }
}

As the code above shows, how can I have the Child.Foo() make a call into GrandParent.Foo() instead of going into Parent.Foo()? base.Foo() takes me to the Parent class first.

Hydric answered 2/8, 2011 at 14:19 Comment(3)
I'm pretty sure that the .net runtime supports this. Related reading blogs.msdn.com/b/ericlippert/archive/2010/03/29/…Coparcener
Perhaps if you state why you want to do this, we could help you rework your architecture?Upcoming
@CodeInChaos: even if it is supported, it will cause ChaosInCode.Hand
H
13

Your design is wrong if you need this.
Instead, put the per-class logic in DoFoo and don't call base.DoFoo when you don't need to.

class GrandParent
{
    public void Foo()
    {
        // base logic that should always run here:
        // ...

        this.DoFoo(); // call derived logic
    }

    protected virtual void DoFoo() { }
}

class Parent : GrandParent
{
    protected override void DoFoo()
    {    
       // Do additional work (no need to call base.DoFoo)
    }
}

class Child : Parent
{
    protected override void DoFoo()
    {  
        // Do additional work (no need to call base.DoFoo)
    }
}
Hand answered 2/8, 2011 at 14:26 Comment(1)
You need to make GrandParent abstract for this to work. Compling this tells you that 'GrandParent.DoFoo()' is abstract but it is contained in non-abstract class 'GrandParent'Chamomile
M
6

I think there is something wrong with your design here. Essentially, you want to "break" the rules of polymorphism. You are saying Child should derive from Parent but want to conveniently skip the implementation in it's parent.

Re-think your design.

Mocha answered 2/8, 2011 at 14:23 Comment(0)
D
3

No. It wouldn't be reliable anyway. You, as the implementer of your class, get to choose your immediate base class. But who is to say that a later release of Parent might not inherit from ParentBase, that in turn inherits from GrandParent? So long as Parent is still implementing the correct contract, this should not cause any issues for those classes inheriting from Parent.

Darbie answered 2/8, 2011 at 14:23 Comment(0)
L
2

No, this isn't possible. Imagine how crazy things would be if this was possible.

If you want something specific skipped in the Child case, consider reworking your design to better represent what you need (e.g. maybe you need to override something else in the Child class, too). Or, you could provide another Foo() in the Parent class that doesn't do anything except call its base.Foo().

Lamented answered 2/8, 2011 at 14:23 Comment(0)
L
1

If you have control of the code, the simplest way is to create a protected method in Parent class that only call base.Foo() and your child class Foo implementation call that method explicitly

Levasseur answered 2/8, 2011 at 14:23 Comment(0)
L
0

We had exactly this scenario on a large project where the derived methods were called from various locations. Due to change management and QA scripts not to be broken, among other constraints, "drastic" refactoring and class re-structuring are not always possible on a large mature project. Also we did not want to override the method and exclude all base functionality. Most solutions seen elsewhere, looked a bit clumsy, but the solution from Josh Jordan on How to call base.base was quite useful.

However we followed the approach below (which I see now is very similar to what Dan Abramov propose).



public class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Hello from Base");
    }
}

public class Derived : Base
{
    public override void Foo()
    {
        base.Foo();
        Console.WriteLine("Text 1");
        WriteText2Func();
        Console.WriteLine("Text 3");
    }

    protected virtual void WriteText2Func()
    {
        Console.WriteLine("Text 2");
    }
}

public class Special : Derived
{
    public override void WriteText2Func()
    {
        //WriteText2Func will write nothing when method Foo is called from class Special.
        //Also it can be modified to do something else.
    }
}   

Litterbug answered 19/5, 2016 at 22:6 Comment(0)
C
0

All these strong opinions...

Sometimes it just makes sense to use 99% of something...

public class Base
{
  public virtual void Foo()
  {
   // Do something
  }
}

public class DerivedLevel1 : Base
{
  public override void Foo()
  {
    DerivedLevel1Foo();
  }
  protected void DerivedLevel1Foo()
  {
    // Do something
    base.Foo();
  }
}

public class DerivedLevel2 : DerivedLevel1
{
  public override void Foo()
  {
   DerivedLevel2Foo();
  }
  protected void DerviedLevel2Foo()
  {
    // Do something
    base.Foo();
  }
}

public class Special : Derived
{
  public override void Foo()
  {
    // Don't do DerivedLevel2Foo()
    base.DerivedLevel1Foo();
  }
}
Cheeseparing answered 16/7, 2020 at 23:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.