Question

Can I get parameter names/values procedurally from the currently executing function?

I would like to do something like this:

public MyFunction(int integerParameter, string stringParameter){
    //Do this:
    LogParameters();
    //Instead of this:
    //Log.Debug("integerParameter: " + integerParameter + 
    //          ", stringParameter: " + stringParameter);

}

public LogParameters(){
    //Look up 1 level in the call stack (if possible),
    //Programmatically loop through the function's parameters/values
    //and log them to a file (with the function name as well).
    //If I can pass a MethodInfo instead of analyzing the call stack, great.
}

I'm not even sure what I want to do is possible, but it would be very nice to be able to automatically output parameter names/values at runtime to a file without explicitly writing the code to log them.

Is it possible?

 45  41054  45
1 Jan 1970

Solution

 22

I realize people linked to other questions which mentioned PostSharp, but I couldn't help posting the code that solved my problem (using PostSharp) so other people could benefit from it.

class Program {
    static void Main(string[] args) {
        Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
        new MyClass().MyMethod(44, "asdf qwer 1234", 3.14f, true);
        Console.ReadKey();
    }
}
public class MyClass {
    public MyClass() {
    }
    [Trace("Debug")]
    public int MyMethod(int x, string someString, float anotherFloat, bool theBool) {
        return x + 1;
    }
}
[Serializable]
public sealed class TraceAttribute : OnMethodBoundaryAspect {
    private readonly string category;

    public TraceAttribute(string category) {
        this.category = category;
    }

    public string Category { get { return category; } }

    public override void OnEntry(MethodExecutionArgs args) {
        Trace.WriteLine(string.Format("Entering {0}.{1}.", 
                                      args.Method.DeclaringType.Name, 
                                      args.Method.Name), category);

        for (int x = 0; x < args.Arguments.Count; x++) {
            Trace.WriteLine(args.Method.GetParameters()[x].Name + " = " + 
                            args.Arguments.GetArgument(x));
        }
    }

    public override void OnExit(MethodExecutionArgs args) {
        Trace.WriteLine("Return Value: " + args.ReturnValue);

        Trace.WriteLine(string.Format("Leaving {0}.{1}.", 
                                      args.Method.DeclaringType.Name, 
                                      args.Method.Name), category);
    }
} 

Simply adding the Trace attribute to a method will cause very nice debugging information to be output, like so:

Debug: Entering MyClass.MyMethod. 
x = 44
someString = asdf qwer 1234
anotherFloat = 3.14
theBool = True
Return Value: 45
Debug: Leaving MyClass.MyMethod.
2010-03-10

Solution

 12

It's theoretically possible with a debug build and optimization turned off, but practically speaking, I suggest you want some source code rewriting pass.

People are going to keep telling you reflection will work when it won't, so here is the function that's actually capable of getting argument values. It's not likely to work reliably with optimization enabled (for example, there might not even be a stack frame when inlining is on) and getting a debugger installed so you can call that function won't be nearly as simple as you were hoping.

2010-03-08