开发者

How to determine if a class is constructed (instance constructor has finished)?

开发者 https://www.devze.com 2023-04-03 10:26 出处:网络
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 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");
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号