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).