views:

687

answers:

5

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

Try to not use var so much, it will allow you to see more of what you are doing.

methodInfo.GetParameters() returns something like a Parameter info array, you should be able to iterate through it to read the values.

ck
I know what types returned to my var are. ParameterInfo does not have a value property. It has a DefaultValue property, which doesn't apply here.
Chris Benard
My bad, I thought the values might be in there. I still think the overuse of var is lazy....
ck
It's outside the scope of this question, but how is it lazy? It's still strongly typed. It's just inferred from the return type of the method/property/operator.
Chris Benard
I don't think it's necessarily "lazy" but I agree that it's a bit overused. If you can easily tell by the right hand side what type you're instantiating, then fine (ie. var dt = new DataTable()) but when you're assigning something to the result of 17 methods chained together, I agree, write it out.
BFree
@Chris Benard: It is strongly types, which means when you have the code in VS its fine, but looking at the code here it can be a bit confusing, like BFree says. Maybe I'm just too set in my ways :)
ck
+1  A: 

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.

Anton Gogolev
A: 

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.

Chris Benard
+1  A: 

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

ShuggyCoUk
+1  A: 

See here:

http://stackoverflow.com/questions/376256/can-you-get-a-list-of-variables-on-the-stack-in-c

I don't think it's possbile, based on all the comments on my answer there. The PropertyInfo class does have a GetValue method, but that requires you to have an actual object of which you want to get the value from.

BFree