Elegant infoof operators in C# (read Info Of)

There’s been some debate on the Eric Lippert blogs (Blog post: In foof We Trust) since there is no equivalent of the typeof() operator for other kinds of code elements. Well, in my current work recently I needed such operator like methodof(…) that would return a MethodInfo, propertyof(…), constructorof(…) fieldof(…) etc… I found a pretty elegant solution on stackoverflow Why is there not a `fieldof` or `methodof` operator in C#?. I found the solution so elegant that I wanted to share it in a blog post. So basically I defined this small class:

using System;

using System.Collections.Generic;

using System.Linq.Expressions;

using System.Reflection;

 

internal static class LinqOp {

   internal static MethodInfo MethodOf<T>(Expression<Func<T>> expression) {

      var body = (MethodCallExpression)expression.Body;

      return body.Method;

   }

   internal static MethodInfo MethodOf(Expression<Action> expression) {

      var body = (MethodCallExpression)expression.Body;

      return body.Method;

   }

   internal static ConstructorInfo ConstructorOf<T>(Expression<Func<T>> expression) {

      var body = (NewExpression)expression.Body;

      return body.Constructor;

   }

   internal static PropertyInfo PropertyOf<T>(Expression<Func<T>> expression) {

      var body = (MemberExpression)expression.Body;

      return (PropertyInfo)body.Member;

   }

   internal static FieldInfo FieldOf<T>(Expression<Func<T>> expression) {

      var body = (MemberExpression)expression.Body;

      return (FieldInfo)body.Member;

   }

}

 

// Sample usage

class Program {

   static void Main() {

      var methodInfo = LinqOp.MethodOf(() => default(List<int>).Add(default(int)));

      var ctorInfo = LinqOp.ConstructorOf(() => new List<int>());

      var fieldInfo = LinqOp.FieldOf(() => String.Empty);

      var propertyInfo = LinqOp.PropertyOf(() => default(String).Length);

   }

}

The magic comes from the fact that the usage of Expression<T> forces the C# compiler to emit an Expression each times the operators are used.

Btw, my friend Jb Evain proposed recently another hack to solve the same infoof problem by directly modifying IL code: parameterof, propertyof, methodof

 

 

 

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://weblogs.asp.net/fmarguerie Fabrice Marguerie
  • http://codebetter.com/members/Patrick-Smacchia/default.aspx Patrick Smacchia

    Hendry, good idea, I actually refactored my original implementation with the idea you submitted. The main motivation is that the C# compiler was emitted pesky warning when using the default(xxx) syntax. So LinqOp methods now looks like:

    internal static PropertyInfo PropertyOf(Expression> expression) {
    var body = (MemberExpression)expression.Body;
    return (PropertyInfo)body.Member;
    }

    internal static FieldInfo FieldOf(Expression> expression) {
    var body = (MemberExpression)expression.Body;
    return (FieldInfo)body.Member;
    }

    // Only one generic parameter for static fields
    internal static FieldInfo FieldOf(Expression> expression) {
    var body = (MemberExpression)expression.Body;
    return (FieldInfo)body.Member;
    }

    internal static MethodInfo MethodOf(Expression> expression) {
    var body = (MethodCallExpression)expression.Body;
    return body.Method;
    }

    internal static MethodInfo MethodOf(Expression> expression) {
    var body = (MethodCallExpression)expression.Body;
    return body.Method;
    }

    internal static ConstructorInfo ConstructorOf(Expression> expression) {
    var body = (NewExpression)expression.Body;
    return body.Constructor;
    }

  • The Countess

    Elegance is learned, my friend

  • Hendry Luk

    Great idea.
    But I dont like the flood of “default” in :
    var methodInfo = LinqOp.MethodOf(() => default(List).Add(default(int)));
    var propertyInfo = LinqOp.PropertyOf(() => default(String).Length);

    Im not on VS right now, but isnt it slightly clearer to make it:
    var methodInfo = LinqOp.MethodOf >(x=>x.Add(default(int)));
    var methodInfo = LinqOp.PropertyOf(x=>x.length);
    ?

  • Dweeberly Loom

    Feels elegant to me:
    http://en.wikipedia.org/wiki/Elegance

    Of course I’m not worry about performance and I have a lot more distance from the specifics than does Eric.

    Still it’s a small bit of code that solves a problem that might otherwise be a good deal more difficult.

  • http://Blogs.msdn.com/ericlippert Eric Lippert

    Though of course the performance cost of building the expression object likely eats up any savings from constructing the info directly from the token.

    This is a pretty common technique for working around the lack of an infoof operator, but I can’t agree that it is *elegant*. It’s kinda hackish in my opinion.

  • http://www.NDepend.com Patrick Smacchia

    Hey Wesner, long time not talking, hope you are well!

    So decompiling …

     

    var methodInfo = LinqOp.MethodOf(() => default(List<int>).Add(default(int)));

     

    …we can see that indeed ldtoken is used:

     

       L_0016: ldtoken instance void [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)

       L_001b: ldtoken [mscorlib]System.Collections.Generic.List`1<int32>

       L_0020: call class [mscorlib]System.Reflection.MethodBase [mscorlib]System.Reflection.MethodBase::GetMethodFromHandle(valuetype [mscorlib]System.RuntimeMethodHandle, valuetype [mscorlib]System.RuntimeTypeHandle)

  • http://wesnerm.blogs.com Wesner Moise

    For performance considerations, do you know if the IL uses ldtoken (faster approach) or passes a string name to Reflection API. In the latter case, it would be best to use the Reflection APIs directly.

    For methods, there is a much better approach that is …

    Convert the method to a delegate and call the Method property of that delegate.

    For properties, fields, and events, it may be best that you attempt to wrap accesses into a method, which you can extract via the same method.