Подтвердить что ты не робот

Как я могу получить значения параметров вызывающего метода?

Вопрос

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

Если это так, я думаю, что это имеет какое-то отношение к использованию свойства MethodBody из объекта MethodInfo, что позволяет вам проверять поток IL, включая свойства, но я не знаю, как это сделать, и я не знаю 'Google не нашел применимый код в 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");
            }
        }
    }
}
4b9b3361

Ответ 1

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

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

Единственный реалистичный способ добиться этого автоматически - через инъекцию кода (через что-то вроде АОП) для создания данных и делать то, что вы хотите, на основе анализа ИЛ.

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

Чтобы быть ясными простыми светоотражающими методами не может достичь желаемого с полной общностью

Ответ 2

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

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

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

Джонатан

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

Ответ 3

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

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

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

Затем используйте класс, упомянутый в ответах (из 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...
                }
            }

Ответ 4

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

Ответ 5

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

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

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