سؤال

I would like to write a reusable function I can call within any method to log a snapshot of all the local variables. For example:

    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);
    }

I would like to get a console output like this:

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

I want to avoid providing a specific list of local variable names.

The closest I could find was MethodInfo.GetCurrentMethod().GetMethodBody().LocalVariables, but I do not know how to access the values of the local variables using reflection.

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);
    }
}

The reflection API seems well suited for static analysis, but not for dynamic analysis like this. For instance, the variable t is not in scope during the first call to dumpLocalVariables, but it still appears in the LocalVariables property of the MethodBody.

I suspect there is a debugging API that I am overlooking. How does Developer Studio populate the "locals" tab when at a breakpoint? Is there a way to do something similar at runtime?

EDIT:

I can see in ILSpy that my example class uses IL codes like ldloc.0 and ldloc.1 to get to the first and second local variable.

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

and later

IL_001b: ldloc.0  // this is a
IL_001c: ldc.i4.1
IL_001d: add
IL_001e: stloc.0
IL_001f: ldloc.1  // this is s
IL_0020: ldstr "else"
IL_0025: call string string::Concat(string, string)
IL_002a: stloc.2  // this is t

Maybe I could use some sort of proxy-like mechanism that lets me do the same thing? I don't mind if the call to my reusable method is messy, I just want something I can paste into any code block without a lot of hand-editing.

لا يوجد حل صحيح

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top