45

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)));
}
Jason
  • 26,250
  • 10
  • 62
  • 62
Sam Harwell
  • 92,171
  • 18
  • 189
  • 263
  • 4
    Can you imagine how many times a year this feature would be used? – John Saunders Jul 31 '09 at 17:36
  • 2
    I'm writing a CLI implementation in C# - it would be extremely helpful for identifying special references in the IL in the JIT so I can treat them differently. For example, I want to replace any IL instance of `call RuntimeHelpers.get_OffsetToStringData` with `ldc.i4 ` inline (before native code generation). – Sam Harwell Jul 31 '09 at 17:40
  • 1
    Fine. How many times a year would this feature be used, worldwide? – John Saunders Jul 31 '09 at 17:48
  • 21
    It's a quite frequently requested feature, so apparently there are reasonably common usage cases. That said, obviously would not achieve the popularity of, say, auto props, or where clauses. – Eric Lippert Jul 31 '09 at 19:43
  • @Eric: I saw on your blog people requesting it for Reflection.Emit - I've run into it there as well. :) On a side note, the C# compiler should compile "typeof(int).TypeHandle" to simply "ldtoken " without going through the property. (sorry I don't know the exact MSIL syntax). – Sam Harwell Jul 31 '09 at 20:11
  • 17
    It would be an extremely used feature for anyone dealing with WPF (think dependency properties), and, more generally, anyone implementing `INotifyPropertyChanged`. – Pavel Minaev Aug 04 '09 at 07:46
  • 2
    Even people who don't use WPF still throw `ArgumentException` – Chris Kerekes Jul 05 '12 at 13:04
  • @ChrisKerekes obviously true, but how is that relevant here? – Sam Harwell Jul 05 '12 at 15:00
  • @280Z28 My previous comment was in response to the comment of @PavelMinaev. The `ArgumentException` constructor overload that takes two strings uses the name of the offending parameter the same way that a `DependencyProperty` is registered. This demonstrates that the need of `fieldof` operator would be of significant use to a broader range of developers besides simply those working on WPF applications. – Chris Kerekes Jul 05 '12 at 18:35
  • related: http://stackoverflow.com/questions/9335126/compile-time-reflection-in-c-sharp http://stackoverflow.com/questions/4229597/why-not-a-memberinfo-reflection-function-for-c-sharp?lq=1 http://stackoverflow.com/questions/11256309/property-of-aka-infoof-via-rosyln – nawfal Apr 10 '13 at 13:43
  • Mind you this approach has a corner case (see http://stackoverflow.com/questions/6658669/lambda-expression-not-returning-expected-memberinfo). I think we're better off not inventing undocumented behaviour.. For methods, I like the solution given here: http://stackoverflow.com/questions/14329433/get-methodinfo-for-any-method-with-any-signature-delegate-for-any-signature – nawfal Dec 13 '13 at 05:34
  • 1
    @JohnSaunders see how many questions are there on stackoverflow related to reflection of type members. In all those cases this is a useful feature. In fact the number of duplicates for this very same requirement itself is too many.. – nawfal Dec 13 '13 at 05:37

4 Answers4

37

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
  • 5,539
  • 1
  • 19
  • 16
  • 4
    +1 For a very elegant solution, plus style points for overloading the cast operators to make it look more built-in. Now if only C# would let us explicitly reference the get/set accessors on properties then this would work on those as well. – BTJ Apr 04 '13 at 05:51
  • 1
    Unfortunately does not work – hazzik Dec 10 '13 at 03:45
  • 1
    @hazzik It works for me. Please specify the error. – IS4 Sep 06 '14 at 10:45
  • I agree it's nice, but unfortunately this requires you to explicitly specify the method signature, so it's basically the same as `MethodInfo parse = ((Func)int.Parse).Method;` which is fully built-in and thus doesn't require any helper class. Seems to me, the whole point here is to avoid that cast, which would enable you to actually ***obtain*** the signature at runtime when all you need to provide at compile-time is the method name token. – Glenn Slayden Jun 24 '17 at 05:05
  • I have problem with `void` (non returned) method. – Cipher Jul 21 '18 at 20:48
23

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
  • 26,250
  • 10
  • 62
  • 62
  • 4
    'Foof' would've been a more appropriate expletive :) – Jason Jul 31 '09 at 17:42
  • 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. – Sam Harwell Jul 31 '09 at 17:44
  • 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. – Sam Harwell Jul 31 '09 at 17:47
7

@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
  • 327
  • 4
  • 12
  • Nicely done. I did something similar here: http://stackoverflow.com/questions/269578/get-a-generic-method-without-using-getmethods/373396#373396 but I like yours as a solid general solution: – Neil Aug 13 '09 at 17:26
  • 3
    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` 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. – Sam Harwell Nov 23 '09 at 15:45
  • Corner case: http://stackoverflow.com/questions/6658669/lambda-expression-not-returning-expected-memberinfo. I think this is not the right approach for this kind of work. Also i think its better to check for unary expressions as in cases of boxed conversions like ` () => IntProperty()`. – nawfal Dec 13 '13 at 05:31
0

this is a generic type version, that can use F2 to rename and not need modify existed code in the example, the method name is GetPKValue

var typFactory = typeof(FormFieldFactory<>).MakeGenericType(entity.GetType());
var methodName = new Func<object, object>(FormFieldFactory<object>.GetPKValue).Method.Name;

var theMethod =
    (Func<object, object>)Delegate.CreateDelegate(
        typeof(Func<object, object>)
        , typFactory.GetMethod(methodName)
    );
IlPADlI
  • 1,657
  • 16
  • 20