【问题标题】:How can I get the values of the parameters of a calling method?如何获取调用方法的参数值?
【发布时间】:2010-10-04 07:17:48
【问题描述】:

问题

我正在编写一些代码,需要能够从调用类的方法中获取参数的值。我知道如何一直到 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");
            }
        }
    }
}

【问题讨论】:

标签: c# reflection dynamic


【解决方案1】:

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

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

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

这通常不是一个好主意,如果您需要调试某些内容,请使用调试器,如果您需要记录某些内容,请明确说明您正在记录的内容。

需要明确的是,简单的反思技术无法全面实现您想要的

【讨论】:

    【解决方案2】:

    Microsoft 的Jonathan Keljo 在this news group post 中说:

    不幸的是,从 今天的 callstack 带有调试器。如果您尝试将其作为 在应用程序中记录错误,并且您计划将错误日志发送回 您的支持部门,我们希望您为此使用小型转储 未来的目的。 (今天,使用托管代码的小型转储是一种 问题不大,因为它没有包含足够的信息,甚至无法获得 默认情况下堆栈跟踪。带有堆的小型转储更好,但不是那么“迷你” 如果你知道我的意思。)

    一个纯粹主义者会说,允许人们编写可以得到 调用堆栈上其他地方的函数的参数会鼓励他们 打破封装并创建在面对以下情况时非常脆弱的代码 改变。 (你的场景没有这个特殊的问题,但我已经 听到其他关于此功能的请求。反正大部分 请求可以通过其他方式解决,例如使用线程存储。)但是, 更重要的是,这会带来安全隐患——应用程序 允许插件将面临这些插件刮取堆栈的风险 敏感信息。我们当然可以将该功能标记为需要 完全信任,但这会使它在几乎所有情况下都无法使用 我听说过。

    乔纳森

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

    【讨论】:

      【解决方案3】:

      是的,你可以这样做。

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

      从这个 SO 问题开始: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...
                      }
                  }
      

      【讨论】:

      • 我没有从最后一行代码中得到值。我得到类似构造函数的信息?这段代码有小问题吗?你测试了吗?
      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        看这里:

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

        我不认为这是可能的,基于我在那里回答的所有 cmets。 PropertyInfo 类确实有一个 GetValue 方法,但这需要您有一个实际的对象来获取值。

        【讨论】:

          【解决方案6】:

          不确定这是否算作一个解决方案,但适用于我的特定案例, 我想在每次修改浮点数时以最少的代码更改记录,

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

          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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-16
            • 2011-06-24
            • 1970-01-01
            • 1970-01-01
            • 2012-04-22
            相关资源
            最近更新 更多