views:

251

answers:

3

I would like to get the name of the method that is being delegated as a Func.

Func<MyObject, object> func = x => x.DoSomeMethod();
string name = ExtractMethodName(func); // should equal "DoSomeMethod"

How can I achieve this?

-- For bragging rights --

Make ExtractMethodName also work with a property invocation, having it return the property name in that instance.

eg.

Func<MyObject, object> func = x => x.Property;
string name = ExtractMethodName(func); // should equal "Property"
A: 

I don't think this is possible in the general case. What if you had:

Func<MyObject, object> func = x => x.DoSomeMethod(x.DoSomeOtherMethod());

What would you expect?

That being said, you could use reflection to open up the Func object and see what it does inside, but you'll only be able to solve it for certain cases.

jcopenha
Given what you have I would want the answer to be "DoSomeMethod".Is it possible that the property example I provided is in fact easier because that would limit the potential complexity of the Func interrogation?
berko
A: 

Check out my hack answer here:

http://stackoverflow.com/questions/1213862/why-is-there-not-a-fieldof-or-methodof-operator-in-c

In the past I did it another way that used Func instead of Expression<Func<...>>, but I was much less pleased with the result. The MemberExpression used to detect the field in my fieldof method will return a PropertyInfo when a property is used.

Edit #1: This works for a subset of the problem:

Func<object> func = x.DoSomething;
string name = func.Method.Name;

Edit #2: Whoever marked me down should take a second to realize what's going on here. The expression trees can be implicitly used with lambda expressions and are the fastest, most reliable way to get the specific requested information here.

280Z28
+10  A: 

Look Ma! No expression trees!

Here's a quick, dirty and implementation-specific version that grabs the metadata token from the IL stream of the underlying lambda and resolves it.

private static string ExtractMethodName(Func<MyObject, object> func)
{
    var il = func.Method.GetMethodBody().GetILAsByteArray();

    // first byte is ldarg.0
    // second byte is callvirt
    // next four bytes are the MethodDef token
    var mdToken = (il[5] << 24) | (il[4] << 16) | (il[3] << 8) | il[2];
    var innerMethod = func.Method.Module.ResolveMethod(mdToken);

    // Check to see if this is a property getter and grab property if it is...
    if (innerMethod.IsSpecialName && innerMethod.Name.StartsWith("get_"))
    {
        var prop = (from p in innerMethod.DeclaringType.GetProperties()
                    where p.GetGetMethod() == innerMethod
                    select p).FirstOrDefault();
        if (prop != null)
            return prop.Name;
    }

    return innerMethod.Name;
}
Dustin Campbell
Thanks! I didn't expect things to get that funky but it works as desired.
berko