How can I get the values of the parameters of a calling method?

31,409

Solution 1

You cannot do it without introspecting the stack yourself (and this is fragile since many optimizations may mean the stack frame is not what you expect, or even that the parameter passed is not in fact what the method signature would suggest (it is perfectly possible for an optimizing JIT compiler to spot that you are only using a sub field of an object/struct and pass that instead).

The ParameterInfo simply tells you the signature of the method as compiled, not the values that were passed.

The only realistic way to achieve this automatically is via code injection (via something like AOP) to create the data and do what you want with it based on analysing the IL.

This is generally not a good idea, if you need to debug something use a debugger, if you need to log something be explicit about what you are logging.

To be clear simple reflective techniques cannot achieve what you desire with full generality

Solution 2

Yes, you can do this.

What you need to do is use an IL disassembler (which is achievable within the System.Reflection.Emit namespace) to find the Operand that contains the parameter value you're looking for.

Start with this SO question: C# reflection and finding all references

Then use the class mentioned in the answers (from Mono.Reflection) to do your inspection. Something like this:

            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...
                }
            }

Solution 3

Jonathan Keljo at Microsoft says, in this news group post, :

Unfortunately, the only easy way to get argument information from a callstack today is with a debugger. If you're trying to do this as part of error logging in an application and you plan to send the error log back to your support department, we're hoping to have you use minidumps for that purpose in the future. (Today, using a minidump with managed code is a little problematic as it does not include enough information to even get a stack trace by default. A minidump with heap is better, but not so "mini" if you know what I mean.)

A purist would say that allowing people to write code that can get arguments from functions elsewhere on the callstack would encourage them to break encapsulation and create code that's very fragile in the face of change. (Your scenario does not have this particular problem, but I've heard other requests for this feature that would. Anyway most of those requests can be solved in other ways, like using thread stores.) However, more importantly there would be security implications of this--applications that allow plugins would be at risk of those plugins scraping the stack for sensitive information. We could certainly mark the function as requiring full-trust, but that would make it unusable for pretty much every scenario I've heard of.

Jonathan

So... I guess the short answer is "I can't." That sucks.

Solution 4

You can't do it with either StackFrame or StackTrace. You can, however, employ some interception framework (such as AOP stuff from Spring.NET) so that you can get hold of parameter values.

Share:
31,409

Related videos on Youtube

Chris Benard
Author by

Chris Benard

I'm a Senior .Net Software Developer in Plano, Texas working remote in the pharmaceutical industry on pharmacy and pharmacy-related software. I do lots of work with old, established technologies like NCPDP EDI and credit card processing. I do mostly backends on distributed, connected systems. Occasionally, I come here to help other people out or get an answer to something I've been banging my head on all day. Links My Blog My GitHub

Updated on July 09, 2022

Comments

  • Chris Benard
    Chris Benard almost 2 years

    Question

    I'm writing some code that needs to be able to get the values of the parameters from the method that called into the class. I know how to get all the way to the ParameterInfo[] array, but I don't know how to then get the values. Is this even possible?

    If it is, I think it has something to do with using the MethodBody property from the MethodInfo object, which allows you to inspect the IL stream, including properties, but I don't know how to do it, and I haven't found applicable code on Google.

    Code

    // 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");
                }
            }
        }
    }
    
  • vbullinger
    vbullinger over 11 years
    I don't get the value from this last line of code. I get something like constructor info? Is there a minor issue with this code? Did you test it?