我有一个基类,它有一个由派生类执行的方法。 该方法由派生类的构造函数以及其中的某些方法或属性引发。 我需要确定它是来自该派生类的实例构造函数内部还是之后(在运行时)。
以下示例说明了我的需求:
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方法也是受欢迎的,因为这是必须的:/。
谢谢!
答案 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 */
}
答案 1 :(得分:3)
漂亮,干净,正确的方式 - 不!我不敢。
Hacky的方式无疑会导致痛苦和痛苦,或许。
将它放在OnSomeEvent
处理程序中:
var whoCalledMe = new StackTrace().GetFrame(1).GetMethod().Name;
如果从构造函数调用,则将为.ctor
;如果从Main
方法调用,则为Raise
。
答案 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");
}
}