C#可重用函数转储局部变量的当前值

时间:2011-05-08 18:28:23

标签: c# debugging reflection local-variables code-reuse

我想编写一个可重用的函数,我可以在任何方法中调用它来记录所有局部变量的快照。例如:

    void somemethod()
    {
        int a = 1;
        string s = "something";
        dumpLocalVariables("step 1", MethodInfo.GetCurrentMethod(), this);

        a++;
        string t = s + "else";
        dumpLocalVariables("step 2", MethodInfo.GetCurrentMethod(), this);
    }

我想得到一个像这样的控制台输出:

step 1
    Int32 a = 1 
    String s = something
step 2
    Int32 a = 2
    String s = something
    String t = somethingelse

我想避免提供一个特定的局部变量名列表。

我能找到的最接近的是MethodInfo.GetCurrentMethod().GetMethodBody().LocalVariables,但我不知道如何使用反射来访问局部变量的值。

void dumpLocalVariables(string context, MethodBase currentMethod, object obj)
{
    Console.WriteLine(context);
    MethodBody methodBody = currentMethod.GetMethodBody();
    foreach (LocalVariableInfo lvi in methodBody.LocalVariables)
    {
        string variableType = lvi.LocalType.Name;
        // how do I get this?
        string variableName = "variableNameHere";
        // how do I get this?    
        string variableValue = "variableValueHere";
        Console.WriteLine("   " + variableType  + " " + variableName + 
            " = " + variableValue);
    }
}

反射API似乎非常适合静态分析,但不适合这样的动态分析。例如,变量t在第一次调用dumpLocalVariables期间不在范围内,但仍显示在LocalVariables的{​​{1}}属性中。

我怀疑有一个我忽略的调试API。 Developer Studio如何在断点处填充“本地人”选项卡?有没有办法在运行时做类似的事情?

编辑:

我可以在ILSpy中看到我的示例类使用IL代码(如ldloc.0和ldloc.1)来获取第一个和第二个局部变量。

MethodBody

以后

.locals init (
    [0] int32 a
    [1] string s
    [2] string t
)

也许我可以使用某种类似代理的机制让我做同样的事情?我不介意调用我的可重用方法是否混乱,我只想要一些我可以粘贴到任何代码块中而无需大量手工编辑的东西。

3 个答案:

答案 0 :(得分:8)

请参阅此相关问题:

Is there a simple way to obtain all the local variables in the current stack frame in C# (or CIL)

简短的回答是:您无法获取局部变量的值,因为它们在运行时直接在堆栈上分配,因此无法通过反射获得。执行此操作的唯一方法是通过调试器API ...而且它远非微不足道。此外,这仅在您的自定义调试器实际附加到流程时才有效。

更好,更可行的选择可能是通过装配编织。您说您不希望方法必须知道在记录其值时要访问的本地变量的特定名称。我建议创建两种方法:

static void LogVariables();

static void LogVariables(params string[] names, params object[] values);

添加一个post build任务,该任务调用一个程序集编织例程,该例程将第一个LogVariables调用与第二个进行交换,但显式地为该方法提供变量名称/值。您可以编写此例程来使用Mono Cecil修改程序集(还有其他工具可以执行此操作)。

http://www.mono-project.com/Cecil

答案 1 :(得分:2)

可以通过将外部调试器用于托管代码。有关完成操作的信息,请参阅“托管调试器示例”:http://blogs.msdn.com/b/jmstall/archive/2004/09/30/236281.aspx(包括示例链接和更多信息)

答案 2 :(得分:0)

使用write minidumps来考虑custom PostSharp aspect (with IL transformation

共享的debuging引擎库,用C#编写。在NuGet上可以作为Microsoft.Samples.Debugging.MdbgEngine。

PostSharp方面的代码在GitHub上可以作为PADRE ( Pluggable Automatic Debugging and Reporting Engine)repository

的一部分提供