Как я могу получить значения параметров вызывающего метода? - PullRequest
20 голосов
/ 29 января 2009

Вопрос

Я пишу некоторый код, который должен иметь возможность получить значения параметров из метода, вызвавшего класс. Я знаю, как добраться до массива ParameterInfo [], но я не знаю, как получить значения. Это вообще возможно?

Если это так, я думаю, что это как-то связано с использованием свойства MethodBody из объекта MethodInfo, который позволяет вам проверять поток IL, включая свойства, но я не знаю, как это сделать, и у меня нет не нашел подходящий код в Google.

код

// Finds calling method from class that called into this one
public class SomeClass
{
    public static void FindMethod()
    {
        for (int i = 1; i < frameCount; i++)
        {
            var frame = new StackFrame(i);
            var methodInfo = frame.GetMethod();
            if (methodInfo.DeclaringType != this.GetType())
            {
                string methodName = frame.GetMethod().Name;
                var paramInfos = methodInfo.GetParameters();

                // Now what?? How do I get the values from the paramInfos

                break;
            }
            else if (i == frameCount - 1)
            {
                throw new TransportException("Couldn't find method name");
            }
        }
    }
}

Ответы [ 5 ]

17 голосов
/ 29 января 2009

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

ParameterInfo просто сообщает вам подпись метода как скомпилированного, а не значения, которые были переданы.

Единственный реалистичный способ достичь этого автоматически - с помощью внедрения кода (через что-то вроде AOP) для создания данных и выполнения с ними необходимых действий на основе анализа IL.

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

Чтобы быть понятным, простые рефлексивные техники не могут достичь того, что вы хотите, с полной общностью

5 голосов
/ 29 января 2009

Джонатан Кельо из Microsoft говорит, в этом сообщении группы новостей ,:

К сожалению, единственный простой способ получить информацию об аргументе от callstack сегодня с отладчиком. Если вы пытаетесь сделать это как часть регистрация ошибок в приложении, и вы планируете отправить журнал ошибок обратно ваш отдел поддержки, мы надеемся, что вы используете мини-дампы для этого цель в будущем. (Сегодня использование минидампа с управляемым кодом немного проблематично, так как не содержит достаточно информации, чтобы даже получить трассировка стека по умолчанию. Минидамп с кучей лучше, но не такой "мини" если вы понимаете о чем я.)

Пурист сказал бы, что позволяет людям писать код, который может получить аргументы из функций в другом месте в callstack побудили бы их нарушить инкапсуляцию и создать код, который очень хрупок перед лицом менять. (Ваш сценарий не имеет этой конкретной проблемы, но я слышал другие запросы на эту функцию, которая будет. Во всяком случае, большинство из них запросы могут быть решены другими способами, например, с использованием хранилищ потоков.) Однако более важно, что это будет иметь последствия для безопасности - приложения которые позволяют плагинам подвергаться риску того, что эти плагины очищают стек для конфиденциальная информация. Конечно, мы могли бы отметить функцию как требующую полное доверие, но это сделало бы его непригодным практически для любого сценария Я слышал о.

Джонатан

Итак ... я думаю, что короткий ответ: "Я не могу". Это отстой.

4 голосов
/ 22 мая 2011

Да, вы можете сделать это.

Вам нужно использовать дизассемблер IL (который достижим в пространстве имен System.Reflection.Emit), чтобы найти операнд, содержащий искомое значение параметра.

Начните с этого вопроса SO: C # отражение и поиск всех ссылок

Затем используйте класс, упомянутый в ответах (из Mono.Reflection), чтобы провести проверку. Примерно так:

            var instructions = method.GetInstructions();
            foreach (var instruction in instructions)
            {
                var methodInfo = instruction.Operand as MethodInfo;
                if(methodInfo == null)
                {
                    continue;
                }
                if (instruction.OpCode.Name.Equals("call") && methodInfo.Name.Equals("YourMethodHere"))
                {
                    var value = (CastToMyType)instruction.Previous.Operand;
                    // Now you have the value...
                }
            }
1 голос
/ 29 января 2009

Вы не можете сделать это ни с StackFrame, ни с StackTrace. Однако вы можете использовать некоторую инфраструктуру перехвата (например, AOP из Spring.NET), чтобы получить значения параметров.

0 голосов
/ 29 января 2009

Смотрите здесь:

Можете ли вы получить список переменных в стеке в C #?

Я не думаю, что это возможно, основываясь на комментариях к моему ответу. Класс PropertyInfo действительно имеет метод GetValue, но для этого необходим фактический объект, значение которого вы хотите получить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...