如何获取调用方法的参数值?

Chr*_*ard 20 c# reflection dynamic

我正在编写一些代码,需要能够从调用类的方法中获取参数的.我知道如何一直到ParameterInfo []数组,但我不知道如何获取值.这甚至可能吗?

如果是,我认为它与使用MethodInfo对象的MethodBody属性有关,它允许你检查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");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Shu*_*oUk 17

如果不自己反省堆栈就不能这样做(这很脆弱,因为许多优化可能意味着堆栈帧不是你所期望的,或者甚至传递的参数实际上并不是方法签名所暗示的(这完全可能是一个优化的JIT编译器,发现你只使用了一个object/struct的子字段并传递了它.

ParameterInfo只是告诉您编译方法的签名,而不是传递的值.

实现这一目标的唯一现实方法是通过代码注入(通过像AOP之类的东西)来创建数据,并根据分析IL做你想做的事情.

这通常不是一个好主意,如果您需要使用调试器进行调试,如果您需要记录一些关于您正在记录的内容.

要明确简单的反光技术无法实现你想要的完全通用性


Chr*_*ard 5

Microsoft的Jonathan Keljo在此新闻组帖子中说:

不幸的是,今天从调用堆栈中获取参数信息的唯一简单方法是使用调试器。如果您尝试在应用程序错误日志记录中执行此操作,并且打算将错误日志发送回支持部门,我们希望以后再使用小型转储。(今天,使用带有托管代码的小型转储会遇到一些问题,因为它不包含足够的信息甚至默认情况下都无法获取堆栈跟踪。带有堆的小型转储更好,但如果您理解我的意思,则不是那么“小型”。)

一个纯粹主义者会说,允许人们编写代码可以从调用堆栈上其他地方的函数获取参数,这会鼓励他们打破封装并创建面对变化非常脆弱的代码。(您的方案没有这个特殊问题,但是我听说过对此功能的其他请求。无论如何,这些请求中的大多数都可以通过其他方式来解决,例如使用线程存储。)但是,更重要的是,这将涉及安全性。其中-允许插件的应用程序将面临那些插件会从堆栈中获取敏感信息的风险。我们当然可以将功能标记为需要完全信任,但这会使它在我听说过的几乎每种情况下都无法使用。

乔纳森

所以...我想简短的答案是“我不能。” 糟透了。


Dan*_*nna 5

是的,你可以这样做。

您需要做的是使用 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...
                }
            }
Run Code Online (Sandbox Code Playgroud)

  • 我没有从最后一行代码中得到值。我得到类似构造函数信息的信息?这段代码有小问题吗?你测试了吗? (4认同)