如何确定是否构造了一个类(实例构造函数已经完成)?

时间:2011-09-08 20:56:12

标签: c# .net reflection

我有一个基类,它有一个由派生类执行的方法。 该方法由派生类的构造函数以及其中的某些方法或属性引发。 我需要确定它是来自该派生类的实例构造函数内部还是之后(在运行时)。

以下示例说明了我的需求:

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
    }
}

问题是我无法更改签名或参数,因为我无法更改派生类。基本上我的想法是确定派生类(发送者)是否完全构建。

所以实现就是这样。我不能在打破派生类的基类中进行更改。我只能对基类进行更改:/

这有可能以某种方式,好还是不好?不幸的是,即使是一些反思魔法或类似的hacky方法也是受欢迎的,因为这是必须的:/。

谢谢!

4 个答案:

答案 0 :(得分:7)

  

这有可能以某种方式......

  

好还是不好?

不。但你已经知道了。

然而,这是一种方法。

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

答案 1 :(得分:3)

漂亮,干净,正确的方式 - 不!我不敢。

Hacky的方式无疑会导致痛苦和痛苦,或许。

将它放在OnSomeEvent处理程序中:

var whoCalledMe = new StackTrace().GetFrame(1).GetMethod().Name;
如果从构造函数调用,则

将为.ctor;如果从Main方法调用,则为Raise

实例:http://rextester.com/rundotnet?code=DBRLC84297

答案 2 :(得分:0)

我正在解释你的(非常严重的!)约束,因为你说你不能改变方法签名,也许不能添加实例字段,但你允许代码更改和静态字段。如果是这样,我的方法涉及设置静态“fromDerivedConstructor”变量并在适当时对其进行测试。 (变量是线程静态的,以便代码是线程安全的。下面的程序打印

NO
NO
YES

按要求: - )

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
    }
  }
}

答案 3 :(得分:0)

这是一个奇怪的问题,无法改变派生但可以改变基础?是吗?

这是一个非常简单的解决方案(我觉得很脏):

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");
    }
}