views:

1174

answers:

4

They could be used as follows:

FieldInfo field = fieldof(string.Empty);
MethodInfo method1 = methodof(int.ToString);
MethodInfo method2 = methodof(int.ToString(IFormatProvider));

fieldof could be compiled to IL as:

ldtoken <field>
call FieldInfo.GetFieldFromHandle

methodof could be compiled to IL as:

ldtoken <method>
call MethodBase.GetMethodFromHandle

Whenever the typeof operator is used, you get perfect Find All References results. Unfortunately, as soon as you go to fields or methods, you end up with nasty hacks. I think you could do the following... or you can go back to getting a field by name.

public static FieldInfo fieldof<T>(Expression<Func<T>> expression)
{
    MemberExpression body = (MemberExpression)expression.Body;
    return (FieldInfo)body.Member;
}

public static MethodInfo methodof<T>(Expression<Func<T>> expression)
{
    MethodCallExpression body = (MethodCallExpression)expression.Body;
    return body.Method;
}

public static MethodInfo methodof(Expression<Action> expression)
{
    MethodCallExpression body = (MethodCallExpression)expression.Body;
    return body.Method;
}

public static void Test()
{
    FieldInfo field = fieldof(() => string.Empty);
    MethodInfo method1 = methodof(() => default(string).ToString());
    MethodInfo method2 = methodof(() => default(string).ToString(default(IFormatProvider)));
    MethodInfo method3 = methodof(() => default(List<int>).Add(default(int)));
}
+12  A: 

Eric Lippert (on the C# design team) has an excellent overview/discussion on this topic here. To quote:

It’s an awesome feature that pretty much everyone involved in the design process wishes we could do, but there are good practical reasons why we choose not to. If there comes a day when designing it and implementing it is the best way we could spend our limited budget, we’ll do it. Until then, use Reflection.

Jason
Dammit! Beat me by seconds.
Jeff Yates
'Foof' would've been a more appropriate expletive :)
Jason
I added a comment under my question with a use case that would be extremely helpful. Of course it could be used - it would just be extremely helpful if I could write C# code to fully leverage the `ldtoken` IL instruction. Or `cpblk` and `initblk` for that matter.
280Z28
I know, I'll implement the hack, then add those helper methods to the list of calls I treat in a special way before the JIT! The only downside is it results in a small JIT-time performance hit, clumsy syntax, and a slightly larger assembly.
280Z28
+1  A: 

I rue the day when reflection becomes this easy. If you thought dynamic SQL was bad this would lead to something a dozen times worse.

Imagine, changing a property name and having to worry about run time errors. /shudder

Spencer Ruport
knives are dangerous in untrained hands, but without them we'd be in the dark ages, at some point you have to be mature enough to wield the weapon.
DevelopingChris
Terrible example since this kind of functionality already exists, you just have to write a bit of code to do it. There's just enough hassle to convey to the developer "this should be your last resort" IMO.
Spencer Ruport
It's a fair point
frou
Your analogy is only valid if you think dynamic sql is bad ;-) there are those of us who embrace dynamic sql
Joel Martinez
@Joel: Dynamic SQL is bad, the problem is there aren't any alternatives that don't have their own set of drawbacks. There are very few occasions where reflection is the best choice.
Spencer Ruport
+4  A: 

@280Z28 - We were just sitting down to figure out how to do this when I found your question & code. We needed a PropertyOf method so I added it. Here it is in case anybody else needs it. Thx for the great question.

     public static PropertyInfo PropertyOf<T>(Expression<Func<T>> expression)
    {
        MemberExpression body = (MemberExpression)expression.Body;
        PropertyInfo pi = body.Member as PropertyInfo;
        if (pi != null)
        {
            return pi;
        }
        else throw new ArgumentException("Lambda must be a Property.");
    } 

      [TestMethod()]
    public void MethodofPropertyOfTest<T>()
    {

        string foo = "Jamming";
        MethodInfo method1 = ReflectionHelper.Methodof(() => default(string).ToString());
        PropertyInfo prop = ReflectionHelper.PropertyOf(() => default(string).Length);
        Assert.AreEqual(method1.Invoke(foo, null), "Jamming");
        Assert.AreEqual(prop.GetGetMethod().Invoke(foo, null), foo.Length);
    }
Terence
Nicely done. I did something similar here:http://stackoverflow.com/questions/269578/get-a-generic-method-without-using-getmethods/373396#373396but I like yours as a solid general solution:
Neil Whitaker
Something to note if you need this type of operation in production code - the value returned by a call to methodof, fieldof, or propertyof is constant for a given input. Whenever I need them in a class, I either have a static readonly field that I initialize to the FieldInfo/MethodInfo/PropertyInfo, or I use an appropriate `Dictionary<Type,MemberInfo>` map. If you look at the IL generated by the expression tree sugar, you can see you don't want to be running that unless you have to. The #1 advantage I see of having them as language operators is the IL could/would be very succinct.
280Z28
+2  A: 

You can actually avoid using both reflection and lambdas (.NET Framework 2.0). Consider the following class:

public class methodof<T>
{
    private MethodInfo method;

    public methodof(T func)
    {
        Delegate del = (Delegate)(object)func;
        this.method = del.Method;
    }

    public static implicit operator methodof<T>(T methodof)
    {
        return new methodof<T>(methodof);
    }

    public static implicit operator MethodInfo(methodof<T> methodof)
    {
        return methodof.method;
    }
}

and it's usage:

MethodInfo writeln = (methodof<Action>)Console.WriteLine;
MethodInfo parse = (methodof<Func<string, int>>)int.Parse;
MagnatLU