Многоразовая функция С# для сброса текущего значения локальных переменных

Я хотел бы написать повторно используемую функцию, которую я могу вызывать в любом методе для регистрации моментального снимка всех локальных переменных. Например:

    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 объекта MethodBody.

Я подозреваю, что есть отладочный API, который я упускаю из виду. Как Developer Studio заполняет вкладку «локальные» в точке останова? Есть ли способ сделать что-то подобное во время выполнения?

РЕДАКТИРОВАТЬ:

В ILSpy я вижу, что мой класс-пример использует коды IL, такие как ldloc.0 и ldloc.1, для доступа к первой и второй локальной переменной.

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

и позже

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

Может быть, я мог бы использовать какой-то прокси-подобный механизм, который позволяет мне делать то же самое? Я не возражаю, если вызов моего повторно используемого метода будет грязным, я просто хочу что-то, что я могу вставить в любой блок кода без большого ручного редактирования.


person hsmiths    schedule 08.05.2011    source источник
comment
Я подозреваю, что есть API отладки, который я упускаю из виду: System.Diagnostics.Debugger   -  person Henk Holterman    schedule 08.05.2011
comment
@Хенк: можешь пояснить? Я не знал, что в классе Debugger есть что-то полезное, кроме IsAttached и Break().   -  person Groo    schedule 08.05.2011
comment
@Hank Holterman & @Groo: System.Diagnostics.Debugger не предлагает ничего, что могло бы помочь в этом случае.   -  person casperOne    schedule 08.05.2011
comment
Зачем кому-то голосовать за комментарий, как будто я подозреваю, что существует API отладки, который я упускаю из виду: System.Diagnostics.Debugger, когда он не предоставляет полезной информации?   -  person Jeff    schedule 08.05.2011
comment
Я проголосовал за него, и в то время это был единственный ответ. Это заставило меня взглянуть на System.Diagnostics, что привело к таким местам, как Environment.StackTrace. К сожалению, это мало помогло.   -  person hsmiths    schedule 08.05.2011


Ответы (3)


См. этот связанный вопрос:

Есть ли простой способ получить все локальные переменные в текущем кадре стека в C# (или CIL)

Короткий ответ: вы не можете получить значения локальных переменных, потому что они выделяются непосредственно в стеке во время выполнения и, следовательно, недоступны через отражение. Единственный способ сделать это — через API отладчика... и это далеко не тривиально. Кроме того, это будет работать только в том случае, если ваш пользовательский отладчик действительно подключен к процессу.

Лучшим и более осуществимым вариантом может быть сборочное плетение. Вы сказали, что не хотите, чтобы метод знал конкретные имена локальных переменных для доступа при регистрации их значений. Я бы предложил создать два метода:

static void LogVariables();

и

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

Добавьте задачу после сборки, которая вызывает процедуру создания сборки, которая заменяет первый вызов LogVariables вторым, но явно предоставляет имена/значения переменных методу. Вы можете написать эту процедуру для изменения сборки с помощью Mono Cecil (есть и другие инструменты, которые могут это сделать).

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

person Jeff    schedule 08.05.2011
comment
Пока это самый простой ответ, но это не то, что я искал. Хотелось бы еще придумать что-то, что можно было бы нормально вставлять и компилировать. - person hsmiths; 09.05.2011
comment
Я думаю, что больше нет идей, поэтому я неохотно принимаю этот ответ. Я думаю, что, по крайней мере, возможно написать что-то, используя сборку cecil во время выполнения, чтобы выполнять такого рода регистрацию без необходимости настройки после компиляции. - person hsmiths; 10.05.2011
comment
если можно получить список локальных переменных, почему невозможно сгенерировать динамический код с помощью Reflection.Emit для сброса его значений? - person gdbdable; 13.09.2013

Это возможно с помощью внешнего отладчика для управляемого кода. См. "пример управляемого отладчика", чтобы узнать, как это делается: http://blogs.msdn.com/b/jmstall/archive/2004/09/30/236281.aspx (содержит ссылку на образец и дополнительную информацию)

person Alexei Levenkov    schedule 08.05.2011
comment
Спасибо за ссылку. Материал mdbg интересно читать. Это потребует гораздо больше работы заранее, но я подозреваю, что смогу приготовить что-то на основе этого, чтобы делать то, что я хочу. Я не думаю, что я одинок в признании закономерности необходимости сбрасывать местных жителей и каждый раз делать это один раз. - person hsmiths; 09.05.2011
comment
Загрузка mdbg v2.0, на которую ссылается блог, больше недоступна. Я нашел загрузку для mdbg v4.0 здесь . (Кто знает, как долго он там пробудет — ему уже почти три года.) - person InteXX; 01.08.2019

Рассмотрите возможность написать минидампы с помощью пользовательский аспект PostSharp (с преобразованием IL) .

Общая библиотека механизма отладки, написанная на C#. доступен в NuGet как Microsoft.Samples.Debugging.MdbgEngine.

Код аспекта PostSharp доступен на GitHub как часть репозитория PADRE (подключаемый модуль автоматической отладки и создания отчетов).

person Michael Freidgeim    schedule 02.12.2012