假设我们有调用methodB() 和methodC() 的methodA()。
在methodB()中,我们调用methodB1()和methodB2()。
在methodC()中,我们调用methodC1()、methodC2()和methodC3()。
所以最后我们有了方法树
方法A
方法B
方法B1
方法B2
方法C
方法C1
方法C2
方法C3
是否可以通过 C# 代码获得此列表?
当我们考虑确定调用流程时,首先想到的是检查调用堆栈。但是检查堆栈帧只能给我们当前的调用层次结构,而不是之前的调用层次结构。即,即使您在 C3 中检查堆栈帧,它也不会有 A 调用 B 的历史记录。所以这不起作用。
这意味着每个被调用的方法也需要以某种方式参与实现这个目标。每个方法都必须以某种方式确定调用者想要跟踪流,并且必须为提供所需信息做出贡献。但是在每个可能调用的方法中添加一些代码是荒谬的。
另一种方法是将其委托给可以拦截每个方法调用的人,检查调用者是否想要跟踪流程并记录以后可以访问的所需信息。这正是我认为面向方面编程(AOP)出现的地方。要在 .Net 中使用 AOP,请查看 PostSharp。如果我有时间,我会尝试提出一些代码示例,但现在我只能指向这个网址:http ://www.postsharp.net
我希望这有帮助。
如果您能够将每个特定操作实现为单独的类(我建议),则如下所示。如果没有,您应该使用AOP。我会推荐用于 AOP 的Castle Dynamic Proxy 。
class Program
{
static void Main(string[] args)
{
new A().Invoke();
CallStack.Get().ToList().ForEach(Console.WriteLine);
Console.ReadKey();
}
}
public class CallStack
{
private CallStack()
{
_callStack = new Stack<string>();
}
private static CallStack _singleton;
private Stack<string> _callStack;
public static CallStack Get()
{
if (_singleton == null) _singleton = new CallStack();
return _singleton;
}
public static void Push(string call)
{
Get()._callStack.Push(call);
}
public List<string> ToList()
{
return new List<string>(_callStack);
}
}
public abstract class MethodBase
{
protected void Trace()
{
CallStack.Push(GetType().Name);
}
protected abstract void Operation();
public void Invoke()
{
Trace();
Operation();
}
}
public class A : MethodBase
{
protected override void Operation()
{
new B().Invoke();
new C().Invoke();
}
}
public class B : MethodBase
{
protected override void Operation()
{
new B1().Invoke();
new B2().Invoke();
}
}
public class C : MethodBase
{
protected override void Operation()
{
new C1().Invoke();
new C2().Invoke();
new C3().Invoke();
}
}
public class B1 : MethodBase
{
protected override void Operation() { }
}
public class B2 : MethodBase
{
protected override void Operation() { }
}
public class C1 : MethodBase
{
protected override void Operation() { }
}
public class C2 : MethodBase
{
protected override void Operation() { }
}
public class C3 : MethodBase
{
protected override void Operation(){}
}