2016-05-20 20 views
0

我试图得到第一个方法名称,发起了多个方法调用。如何在C#中的多个子方法中找到父方法名?

,比如我有以下,

static void Main(string[] args) 
    { 
     Test1(); 
    } 

    static void Test1() 
    { 
     Test2(); 
    } 
    static void Test2() 
    { 
     Console.WriteLine("Soemthing"); 
    } 

在Test2的方法,我需要知道的主要方法已经启动了这一链条。 我尝试使用StackTrace和Reflection如下。

 StackTrace stackTrace = new StackTrace(); 
     MethodBase methodBase = stackTrace.GetFrame(1).GetMethod(); 
     Console.WriteLine(methodBase.Name); 

stackTrace.getFrame(1)不是我所期望的。它会给我以前的方法是Test1。

我不想将getFrame值硬编码为以获取Main方法。

有没有办法从任何子方法获得父方法没有硬编码帧值?

+0

如果您想手动执行此操作,您可以右键单击该方法,然后单击Go To Deifnition或Peek Definition,继续这样做,直到找到所需的父级。但自动im不知道 – Brendon

+4

“初始方法”的标准是什么?在单线程控制台应用程序中,它始终是'Main',不需要确定它...在Web服务中,您可以通过IIS程序集爬取... –

+0

我这样做只是为了研究。但最终我们会使用MVC 6 WebAPi。@RenéVogt –

回答

2

这会做你想要什么:

var stackTrace = new StackTrace(); 
string lastCSharpMethodName = null; 
for (int i = 0;; i++) 
{ 
    if (stackTrace.GetFrame(i).GetILOffset() == StackFrame.OFFSET_UNKNOWN) 
     break; 

    lastCSharpMethodName = stackTrace.GetFrame(i).GetMethod().Name; 
} 

Console.WriteLine(lastCSharpMethodName); 

如果你在VS调试器仔细观察,你会看到,呼吁建立一个控制台应用程序(作为一个例子),第一种方法是本地mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()这是在语言部分标记为Unknown

enter image description here

以上代码的作用是过滤出unknown,并返回第一个已知行(请参阅:https://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe.getiloffset(v=vs.110).aspx)。

这是你的情况是Main()

+0

这给了我想要的答案。但我试图找出一种方法来做到这一点没有循环。 此外我想申请这个WebApi,看看会发生什么。 谢谢。 –

+0

它也适用于WebApi。 :)现在要找出一种没有循环的方法。 –

+0

很高兴听到它。不知道有没有一种方法可以做到这一点没有循环,但祝你好运。 – kha

0

我想你不是在寻找堆栈中的第一帧,而是最后一帧。 随着FrameCount属性,你可以写这样的事情:

StackTrace stackTrace = new StackTrace(); 
MethodBase methodBase = stackTrace.GetFrame(stackTrace .FrameCount - 1).GetMethod(); // Not sure about the "- 1" 
Console.WriteLine(methodBase.Name); 

但是,如果我记得很清楚,有一些与堆栈调用切堆栈的下一个电话。 (当你在堆栈上进行第二次调用时,你不应该看到以前的方法调用。)

但我不确定。

+0

是@ romain-aga它也给我“ThreadStart” –

+0

您可以使用“ - 2”代替。但它只适用于这种情况。也许你将不得不浏览所有的堆栈,直到你到达ThreadStart或者结束,并保存前一个项目以找到你正在寻找的东西。 –

0

您可以使用此方法来确定您的调用堆栈的顶部(或更好的底部)方法的名称:

private static string GetInitialCaller() 
{ 
    StackTrace trace = new StackTrace(); 
    StackFrame frame = trace.GetFrames()?.LastOrDefault(); 
    return frame?.GetMethod()?.Name; 
} 

测试它在一个控制台应用程序一样,

private static void TestIt() 
{ 
    string caller = GetInitialCaller(); 
    Console.WriteLine($"Initial caller: {caller}"); 
} 
private static void Main() 
{ 
    TestIt(); 
} 

输出:

Initial caller: Main 
+0

经过测试。但它给了我“ThreadStart” –

+0

它是主要的来电者,如果你达到一个等级,你应该找到主要的。但即使你尝试我的方法,你也会遇到一些问题。就像我在我的回答中所说的那样,堆栈可以根据你调用它的位置/时间来切割。 –

+0

顺便说一句@RenéVogt,很好的使用4.6功能:) –

0

使用@kha的回答,这应该做的伎俩同出一环。

  List<StackFrame> list = new StackTrace().GetFrames().ToList(); 
      int index = list.FindIndex(p => p.GetILOffset() == StackFrame.OFFSET_UNKNOWN); 
      var methodName = list.Select(p => p.GetMethod().Name).ElementAt(index-1); 
相关问题