20

我希望能够从 .NET 中的堆栈帧中获取所有参数值。有点像在 Visual Studio 调试器中查看调用堆栈中的值的方式。我的方法集中在使用StackFrame 类,然后反映在ParameterInfo数组上。我在反射和属性方面取得了成功,但这证明有点棘手。

有没有办法实现这一目标?

到目前为止的代码如下所示:

class Program
{
    static void Main(string[] args)
    {
        A a = new A();
        a.Go(1);
    }
}

public class A
{
    internal void Go(int x)
    {
        B b = new B();
        b.Go(4);
    }
}

public class B
{
    internal void Go(int y)
    {
        Console.WriteLine(GetStackTrace());

    }
    public static string GetStackTrace()
    {
        StringBuilder sb = new StringBuilder();
        StackTrace st = new StackTrace(true);
        StackFrame[] frames = st.GetFrames();

        foreach (StackFrame frame in frames)
        {
            MethodBase method = frame.GetMethod();

            sb.AppendFormat("{0} - {1}",method.DeclaringType, method.Name);
            ParameterInfo[] paramaters = method.GetParameters();
            foreach (ParameterInfo paramater in paramaters)
            {
                sb.AppendFormat("{0}: {1}", paramater.Name, paramater.ToString());
            }
            sb.AppendLine();
        }
        return sb.ToString();
    }
}

输出如下所示:

SfApp.B - GetStackTrace
SfApp.B - Go
y: Int32 y
SfApp.A - Go
x: Int32 x
SfApp.Program - Main
args: System.String[] args

我希望它看起来更像这样:

SfApp.B - GetStackTrace
SfApp.B - Go
y: 4
SfApp.A - Go
x: 1
SfApp.Program - Main

只是为了一点背景,我的计划是在我抛出自己的异常时尝试使用它。我会更详细地查看您的建议,看看是否合适。

4

2 回答 2

8

好像不能那样做。它只会提供有关方法及其参数的元信息。不是调用堆栈时的实际值。

有些人建议从ContextBoundObject派生您的类,并使用IMessageSink来通知所有方法调用和参数值。这通常用于.NET Remoting

另一个建议可能是编写一个调试器。这就是 IDE 获取信息的方式。Microsoft 有Mdbg,您可以从中获取源代码。或者编写一个CLR 分析器

于 2008-09-16T18:13:42.390 回答
0

我很确定这是可能的,但我没有足够的能力给你你想要的答案。我建议一种不同的方法,虽然不太灵活,但如果您事先有堆栈跟踪并且您希望查看传递给每个帧的参数,那么它仍然有用。

通常,您会在堆栈跟踪中存在的每个方法的开头分散日志消息,但这非常麻烦并且并不总是可能的:如果您调用外部库中定义的方法怎么办?


当我在寻找如何解决这个问题的灵感时,我发现了一个名为Harmony的库,它允许您在运行时修补方法。基本上,方法可以用前缀、后缀和/或终结器装饰。文档中对此进行了很好的解释,但是您可以用来在堆栈跟踪中提供有关方法的详细信息的想法是创建一个打印每个帧的参数的前缀

不幸的是,仅使用 Harmony,我认为StackTrace即使使用后缀/终结器,也无法像您想要的那样对 current 中的方法执行此操作。尽管如此,它可以在调用目标方法之前完成。


我创建了一个非常简单的库,称为DebugLogger内部使用 Harmony 并简化了过程。是存储库,但您也可以在 Nuget 上找到它:

dotnet add package DebugLogger --version 1.0.0

它仍然有很多限制,部分是因为 Harmony,只有一堆测试,还没有准备好被视为一个库,但在我看来这是一个很好的起点。我准备了一个小提琴,展示了初始化DebugLogger和几个虚拟类,以使演示“有意义”。

于 2022-01-02T01:27:11.253 回答