0
public class C1 {
    public virtual void A() { Console.WriteLine("Good"); }
    public void B() { A(); } // <-- wrong A when when called in child classes :(
}
public class C2 : C1 {
    public override void A() { B(); }
}

Is there anything I can do in C2 such that when C2.A() calls B() the next call is to C1.A() instead of C2.A() which leads to infinite recursion?

Sparr
  • 7,489
  • 31
  • 48
  • 1
    You can't do as you want because that's not how overrides work. Why would you call B from overriden A? – ProgrammingLlama Nov 30 '18 at 04:46
  • 2
    For me it seems only like a wrong design. The only way I know is, the `C1.B()` and `C1.A()` should both call a private `C1.PrivateA()`. – Julo Nov 30 '18 at 04:47
  • 2
    Seems you have to re-consider your design. – Klaus Gütter Nov 30 '18 at 04:47
  • Possible duplicate of [Difference between shadowing and overriding in C#?](https://stackoverflow.com/questions/392721/difference-between-shadowing-and-overriding-in-c) – mjwills Nov 30 '18 at 05:35

4 Answers4

0

Wouldn't this simply be enough? Move the implementation of A into a separate, private, method in the base class, then call that instead from the base class?

public class C1 {
    private void AImplementation() { Console.WriteLine("Good"); }
    public virtual void A() { AImplementation(); }
    public void B() { AImplementation(); }
}
public class C2 : C1 {
    public override void A() { B(); }
}
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
0

Knowing that you're in full on hack mode helps. This hack probably works in more scenarios than the other suggestion. But it is omgway slower. This implementation tries to be as generic as possible. But, you could probably just grab the frame at the appropriate hardcoded index & check/compare declaring types if you only wanted to solve this particular example.

public class C1 {
    public virtual void A() { Console.WriteLine("Good"); }
    public void B() { A(); }
}
public class C2 : C1 {
    public override void A()
    {
        var method = new System.Diagnostics.StackTrace()
                    .GetFrames().Skip(1).Select(f => f.GetMethod())
                    .FirstOrDefault(m => m.Name == nameof(A) && m.DeclaringType == typeof(C2));
        if (method == null) B();
        else base.A();
    }
}

Or, like I said you could just check if

var method = new System.Diagnostics.StackTrace().GetFrame(2).GetMethod();
if (method.Name != nameof(A)) B();
else base.A();

As everyone else has said though, this is a terrible solution that you'd fix with better design if you could.

Jeff Hamm
  • 51
  • 3
-1

A helpful person on IRC provided this hacky non-thread-safe solution:

public class C1 {
    public virtual void A() { Console.WriteLine("Good"); }
    public void B() { A(); }
}
public class C2 : C1 {
    bool _aOnCallStack = false;
    public override void A() { 
        if (!_aOnCallStack) {
            _aOnCallStack = true;
            B(); 
        }
        else {
            base.A();
            _aOnCallStack = false;
        }
    }
}
Sparr
  • 7,489
  • 31
  • 48
  • This hack may help your, but this will not solve the bad design, I can not imagine a reason, why you would need such a design. When the `C1.B()` needs to call a specific `A()` methos, this method should not be overridden. And when the `C1.B()` method should call corresponding overridden method, then the overridden `C2.A()` should not call `C1.B()` to create a recursion. – Julo Nov 30 '18 at 04:57
  • C2.A() needs to accomplish all of the things that C1.B() already does. NOT calling it would involve a lot of otherwise-unnecessary code duplication. – Sparr Nov 30 '18 at 04:59
  • @Sparr Perhaps you could provide a more realistic scenario? I genuinely can't think of a reason why you would ever need to do this. – ProgrammingLlama Nov 30 '18 at 05:00
  • 3
    @Sparr that may be true, then you should make a `C1.PrivateA()` or `C1.ProtectedA()` that will be called from `C1.B()` and `C1.A()` and there is no recursion problem. The problem is, that `C1.B()` needs to call `any.A()` and one of the `any.A()` calls `C1.B()`, what causes recursion. – Julo Nov 30 '18 at 05:07
  • @John C1 implements selecting one or more items from a list. It has one() and many() methods. many() has some checks and a loop that calls one(). C1 defines-by-example an interface that other list selection process classes need to follow. I am implementing C2, which provides a different way to select one or more items. C2's primary entry point is one(), but the result will be multiple selections. All that functionality already exists in C1.many() and C1.one(), so I'd like to call many() and have it call C1.one() so I can avoid duplicating all the code from C1.many() in C2.one(). – Sparr Nov 30 '18 at 05:10
  • 1
    You simple need to separate the identical part, e.g. `protected C1.common()` to a protected function, that will be called from `C1.many()` and `C2.one()`. – Julo Nov 30 '18 at 05:14
  • I think Julo is right. @Julo perhaps you could provide that as an answer for OP? – ProgrammingLlama Nov 30 '18 at 05:15
  • I do not have control over the contents of C1, or the instanciation of C2. Exactly one C2 is going to be created, and C2.A() is going to be called. That is why the very hacky solution that we are currently commenting on is the best solution available so far. – Sparr Nov 30 '18 at 05:16
  • This is bad. Then at least make a `lock` to make this thread safe. But when it works with GUI controls, then lock may be not necessary, since GUI controls can not be used from from other threads. Unfortunately I have no better idea with this limitations. – Julo Nov 30 '18 at 05:20
  • @Julo thanks for the `lock` suggestion. I didn't know about that, and that's a lot easier than implementing thread locks myself. If I use this solution, I will do it with a lock, and update this answer. – Sparr Nov 30 '18 at 05:25
-1

I had to rename your classes and methods - the As, Bs and Cs were driving me nuts.

NOTE: This is a redo, after your comment that the base class had to be left alone. I think this answers your question. It's hacky, but I think it should work:

public class Base {
    public virtual void TheVirtualFunction() {
        Console.WriteLine($"Base Class Implemenation of Virtual Function from type {GetType().Name}");
    }
    public void NonVirtualFuction() {
        Console.WriteLine($"The non-Virtual Function - Calling Vitual function now from type {GetType().Name}");
        TheVirtualFunction();
    }
}

public class Sub : Base
{
    private bool _isCallingAgain = false;
    public override void TheVirtualFunction()
    {
        Console.WriteLine($"Sub Class Implemenation of Virtual Function from type {GetType().Name}");
        if (_isCallingAgain)
        {
            Console.WriteLine($"Skipping because v-func called twice from type {GetType().Name}");
            return;
        }
        _isCallingAgain = true;
        Console.WriteLine($"This pass through the virtual function does something (from type {GetType().Name})");
        NonVirtualFuction();
        _isCallingAgain = false;
    }
}

Then, in my Main function, I have code that looks like:

static void Main(string[] args) {
    var theBase = new Base();
    Console.WriteLine("Calling Base Class Non Virtual function");
    theBase.NonVirtualFuction();

    Console.WriteLine("\r\nCalling Base Class Virtual function directly");
    theBase.TheVirtualFunction();

    var theSub = new Sub();
    Console.WriteLine("\r\nCalling Non-Virtual Function (implemented in the base class) using sub-class reference");
    theSub.NonVirtualFuction();

    Console.WriteLine("\r\nCalling Sub Class Virtual function directly");
    theSub.TheVirtualFunction();

    Console.ReadLine();
}

The result of all that is this spew to the console:

Calling Base Class Non Virtual function
The non-Virtual Function - Calling Vitual function now from type Base
Base Class Implemenation of Virtual Function from type Base

Calling Base Class Virtual function directly
Base Class Implemenation of Virtual Function from type Base

Calling Non-Virtual Function (implemented in the base class) using sub-class reference
The non-Virtual Function - Calling Vitual function now from type Sub
Sub Class Implemenation of Virtual Function from type Sub
This pass through the virtual function does something (from type Sub)
The non-Virtual Function - Calling Vitual function now from type Sub
Sub Class Implemenation of Virtual Function from type Sub
Skipping because v-func called twice from type Sub

Calling Sub Class Virtual function directly
Sub Class Implemenation of Virtual Function from type Sub
This pass through the virtual function does something (from type Sub)
The non-Virtual Function - Calling Vitual function now from type Sub
Sub Class Implemenation of Virtual Function from type Sub
Skipping because v-func called twice from type Sub

Note that it calls the sub-class virtual function twice, but a guard bit keeps it from doing anything on the second time through. This is pretty much what you came up with, but I did it independently.

The guard bit (_isCallingAgain) is a private instance member variable. It is necessarily accessed on a single thread of execution (the path of execution comes into the Sub's v-func, goes up into the Base's non-virtual function, and then comes back into the Sub's v-func again). There's no need to guard it with a lock or another else (other than making sure it is private).

I think this (or a variation on this) is your only choice. A non-reentrancy guard like this is a pretty common pattern (it was very common back in the day when I did MFC and Win32 Windows UI programming).

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • Thank you for making me realize I had not specified in my question that I am looking for a solution that can be implemented in the definition of the child class. – Sparr Nov 30 '18 at 05:40
  • @Sparr: I redid my code. I believe my base class is a reflection of your base class. My sub-class does all the weird work required to meet your needs. I think (but I'm not sure) that it should do what you want. If not, it may be modifiable to get it to work. – Flydog57 Nov 30 '18 at 07:08
  • Damn, I just realized that it's basically the same as your code. But, it's a bit different (your code is a bit simpler, I think mine is a little clearer). Anyways... Good luck. – Flydog57 Nov 30 '18 at 07:11
  • re `lock`, what happens if two different threads call that same instance's method around the same time? – Sparr Dec 01 '18 at 13:52
  • Well, yeah, then you'd need a lock – Flydog57 Dec 01 '18 at 15:43