I have a base class that has a method that gets executed by derived classes. The method is raised by a constructor of the derived class and by some methods or properties in it. I need to determine if that came from inside the instance constructor of that derived class or after that (in runtime).
The following example explains what I need:
public class Base
{
public Base()
{
}
protected void OnSomeAction(object sender)
{
// if from derived constructor EXIT, else CONTINUE
}
}
public class Derived : Base
{
public void Raise()
{
base.OnSomeAction(this); // YES if not called by constructor
}
public Derived()
{
base.OnSomeAction(this); // NO
Raise(); // NO
}
}
class Program
{
static void Main(string[] args)
{
var c = new Derived(); // NO (twice)
c.Raise(); // YES
}
}
The problem is that I cannot change the signature or arguments because I cannot alter derived classes. Basically what I was thinking is to determine if the derived class (sender)开发者_开发问答 is fully constructed.
So the implementation is as is. I cannot do changes in the base class that break derived classes. I can do changes only to the base class :/
Is this possible in some way, good or not? Even some reflection magic or similar hacky approach is unfortunately welcome as this is a must :/.
Thanks!
Is this possible in some way...
Yes
good or not?
Not. But you already knew that.
Nevertheless, here is one way to do it.
protected void OnSomeEvent( object sender, EventArgs e )
{
var trace = new StackTrace();
var frames = trace.GetFrames();
for ( int idx = 0; idx < frames.Length; idx++ )
{
MethodBase method;
method = frames[idx].GetMethod();
if ( method.ReflectedType == typeof(Derived) && method.IsConstructor )
{
return;
}
}
/* Perform action */
}
source
Nice, clean, proper way - No! Im afraid not.
Hacky way which will no doubt lead to pain and suffering, Perhaps.
Put this inside your OnSomeEvent
handler:
var whoCalledMe = new StackTrace().GetFrame(1).GetMethod().Name;
will rad .ctor
if called from the constructor, or Main
when called from Raise
method.
Live example: http://rextester.com/rundotnet?code=DBRLC84297
I'm interpreting your (very severe!) constraints as saying you can't change method signatures and perhaps can't add instance fields, but you will allow code changes and static fields. If so, my approach involves setting a static "fromDerivedConstructor" variable and testing it as appropriate. (The variable is made thread-static in order for the code to be threadsafe. The below program prints
NO
NO
YES
as requested :-)
using System;
using System.Diagnostics;
namespace ConsoleApplication33 {
public class Base {
[ThreadStatic]
protected static bool fromDerivedConstructor;
public Base() {}
protected void OnSomeAction(object sender) {
// if from derived constructor EXIT, else CONTINUE
if(fromDerivedConstructor) {
Debug.WriteLine("NO");
return;
}
Debug.WriteLine("YES");
}
}
public class Derived : Base {
public void Raise() {
base.OnSomeAction(this); // YES if not called by constructor
}
public Derived() {
fromDerivedConstructor=true;
try {
base.OnSomeAction(this); // NO
Raise(); // NO
} finally {
fromDerivedConstructor=false;
}
}
}
internal class Program {
private static void Main(string[] args) {
var c=new Derived(); // NO (twice)
c.Raise(); // YES
}
}
}
This is a weird problem, not being able to change the derived but can change the base? Eh?
Here's a very simple solution (I feel dirty):
public class Base
{
private event EventHandler SomeEvent;
private int initCount = 0;
public Base()
{
}
protected void OnSomeEvent(object sender, EventArgs e)
{
// if from derived constructor EXIT
switch (initCount)
{
case 0:
initCount += 1;
Console.WriteLine("NO");
return;
case 1:
initCount += 1;
this.SomeEvent += new EventHandler(OnSomeEvent);
Console.WriteLine("NO");
return;
}
// else CONTINUE
Console.Write("YES");
}
}
精彩评论