C#如何在多个子方法中查找父方法名?

How to find the parent method name in multiple sub methods in C#?

我正在尝试获取启动多个方法调用的第一个方法名称。

例如我有下面的,

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

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

在Test2 方法中,我需要知道Main 方法启动了这个链。 我尝试如下使用 StackTrace 和 Reflection。

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

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

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

有没有办法在不对帧值进行硬编码的情况下从任何子方法中获取父方法?

我猜您不是在寻找堆栈中的第一帧,而是在寻找最后一帧。 使用 FrameCount 属性,你可以这样写:

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

但是,如果我没记错的话,堆栈调用中有一些东西会为下一次调用切断堆栈。 (当你在堆栈上进行第二次调用时,你应该看不到之前的方法调用。)

但我不确定。

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

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

这会做你想做的事:

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语言部分:

.

上面的代码所做的是过滤掉 unknown 和 return 第一个已知行(参见:https://msdn.microsoft.com/en-us/library/system.diagnostics.stackframe.getiloffset(v=vs.110).aspx)。

你的情况是Main()

使用@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);