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

时间:2009-01-29 17:27:51

标签: 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");
            }
        }
    }
}

6 个答案:

答案 0 :(得分:17)

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

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

自动实现此目的的唯一现实方法是通过代码注入(通过类似AOP之类的东西)来创建数据,并根据分析IL执行您想要的操作。

这通常不是一个好主意,如果你需要使用调试器来调试某些东西,如果你需要记录一些关于你正在记录的内容。

要明确简单的反思技巧不能以完全的普遍性实现您的愿望

答案 1 :(得分:5)

微软的Jonathan Keljo在this news group post中说:

  

不幸的是,从a获取参数信息的唯一简单方法   今天的callstack是一个调试器。如果你试图这样做的一部分   错误登录应用程序并计划将错误日志发送回   你的支持部门,我们希望你能使用minidumps   未来的目的。 (今天,使用托管代码的minidump是一个   这个问题很少,因为它不包含足够的信息来获得一个   默认情况下堆栈跟踪。带堆的minidump更好,但不是那么“迷你”   如果你知道我的意思。)

     

纯粹主义者会说允许人们编写可以获得的代码   来自callstack其他地方的函数的参数会鼓励他们   打破封装并创建面对非常脆弱的代码   更改。 (你的情况没有这个特殊的问题,但我已经   听说过这个功能的其他要求。无论如何大多数   请求可以通过其他方式解决,例如使用线程存储。)但是,   更重要的是,这会对安全性产生影响 - 应用程序   允许插件存在那些插件刮掉堆栈的风险   敏感的信息。我们当然可以将该功能标记为要求   完全信任,但这会使它几乎无法用于所有场景   我听说过。

     

Jonathan

所以...我想简短的回答是“我不能。”太糟糕了。

答案 2 :(得分:4)

是的,你可以这样做。

您需要做的是使用IL反汇编程序(可在System.Reflection.Emit命名空间中实现)来查找包含您正在查找的参数值的操作数。

从这个问题开始:C# reflection and finding all references

然后使用答案中提到的类(来自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...
                }
            }

答案 3 :(得分:1)

您无法使用StackFrame或StackTrace执行此操作。但是,您可以使用一些拦截框架(例如Spring.NET中的AOP),以便您可以获取参数值。

答案 4 :(得分:0)

见这里:

Can you get a list of variables on the stack in C#?

根据对我的回答的所有评论,我不认为这是可能的。 PropertyInfo类有一个GetValue方法,但是这需要你有一个你想从中获取值的实际对象。

答案 5 :(得分:0)

不确定这是否可以作为解决方案,但可以用于我遇到的特定情况, 我想在每次代码修改最少的情况下修改一次浮动记录,

在堆栈跟踪行上读取文件以找出参数

public static Score operator +(Score x,float y) {
    var st = new StackTrace(true);
    var sf = st.GetFrame(1);                
    string paramName = File.ReadLines(sf.GetFileName()).ElementAtOrDefault(sf.GetFileLineNumber()-1).Split(new[] { "+=" }, StringSplitOptions.None)[1];
            
    x.DebugString += (paramName+" "+y);
    x.DebugString += System.Environment.NewLine;
            
    x.val += y;
    return x;
}
            
            
void Main(){
    Score score = new Score();
    float firstScore = 2;
    float secondScore = -13;
    score+=firstScore;
    score+=secondScore;
    Console.WriteLine(score.DebugString);
}
        
Output : 
firstscore  2
secondScore -13
相关问题