CallerMemberName and runtime code

CallerMemberNameAttribute

As of .net 4.5 we now have CallerMemberNameAttribute

So now we can have this class

public class MyClass
{
    public void Method([CallerMemberName] string name = "")
    {
        Debug.WriteLine(name);
    }
}

And when called as such

public void CompileTime()
{
    var myClass = new MyClass();
    myClass.Method();
}

The output will be "CompileTime". The reason is that the method call is compiled to

myClass.Method("CompileTime");

Pretty cool right?

So what happens when we mix this sugar with some runtime features

Dynamic

Using the dynamic keyword we can produce equivalent code to the "CompileTime" method.

public void Dynamic()
{
    var myClass = new MyClass();
    var dynamic = (dynamic)myClass;
    dynamic.Method();
}

Now you might expect to get output of "Dynamic" however instead we get an empty string. This is because rather than respecting the CallerMemberNameAttribute the runtime respects the the default value for the "name" parameter.

Reflection

How about we again produce equivalent code but using reflection

public void Reflection()
{
    var myClass = new MyClass();
    var method = typeof(MyClass).GetMethod("Method");
    method.Invoke(myClass, null);
}

Well this results in a "TargetParameterCountException : Parameter count mismatch.". This one surprised me. I was expecting it to at least respect the default value for the "name" parameter the same way the dynamic scenario did.

Delegate

How about when a delegate is created to a method containing CallerMemberName. So for example.

public void Delegate()
{
    var myClass = new MyClass();
    var action = new Action(() => myClass.Method());
    CallAction(action);
}

void CallAction(Action action)
{
    action();
}

Now while the intent here may have been to get "CallAction" outputted the actual output is "Delegate". This is not surprising when you remember CallerMemberName is a compile time feature. So the action construction actually compiles to

new Action(() => myClass.Method("Delegate"));

In Summary

The important thing to remember is that CallerMemberName is a compile time feature. So don't expect it to add any value to dynamic code. The same applies to CallerFilePath and CallerLineNumber.

Posted by: Simon Cropp
Last revised: 08 Apr, 2012 11:06 AM History

Comments

No comments yet. Be the first!

No new comments are allowed on this post.