It's exactly what it says on the can.

2008-09-18

Typesafe Reverse Reflection

No, reverse reflection isn't a hall of mirrors. I'm talking about those instances where you need to specify the name of a property of an object which will get used by some component later on to access your object via reflection. Specifically, passing a white-list of property names to ASP.NET MVC's UpdateModel controller method.

Specifying property names in this way has always bugged me. If you decide to change a property name, the compiler can't catch if for you and your program will silently start to fail. What we need, is a way to allow the compiler to catch this situation for you.

The code below shows how this can be achieved for methods and members (properties and fields).

public static class ObjectUtils
{
    public static string GetMemberName<T>(Expression<Func<T, object>> action)
    {
        var lambda = (LambdaExpression)action;
        var unary = (UnaryExpression)lambda.Body;
        var operand = unary.Operand;
        if (ExpressionType.MemberAccess == operand.NodeType)
        {
            var memberExpr = (MemberExpression)operand;
            return memberExpr.Member.Name;
        }
        else if (ExpressionType.Call == operand.NodeType)
        {
            var methodExpr = (MethodCallExpression)operand;
            return methodExpr.Method.Name;
        }
        throw new InvalidOperationException();
    }
}
public class Program
{
    public int SomeInt { get; set; }
    public int getSomeInt() { return SomeInt; }
static void Main()
    {
        string propName = ObjectUtils.GetMemberName<Program>(p => p.SomeInt);
        string funcName = ObjectUtils.GetMemberName<Program>(p => p.getSomeInt());
    }
}

This could be useful in an ASP.NET MVC controller that made a call such as the following:

public interface Product
{
    int Id {get; set; }
    string Name {get; set; }
    decimal UnitPrice {get; set; }
}
public class ProductController : Controller
{
    [AcceptVerbs("POST")]
    public ActionResult Edit(int id, FormCollection fc)
    {
        var entity = dataContext.Products.Single(e => e.Id == id);
UpdateModel(
            entity,
            new[] { "Name", "UnitPrice" }
        );

        // ...
    }
    //...
}

As you can see, in the UpdateModel(...) call we are specifying the 'Name' and 'UnitPrice' properties using a string. Now, if we use GetMemberName method, we can have something that the compiler can understand:

   UpdateModel(
        entity,
        new[] {
            ObjectUtils.GetMemberName<Product>(p => p.Name),
            ObjectUtils.GetMemberName<Product>(p => p.UnitPrice),
        }
    );

My biggest problem with this is that it's very verbose. What I'd really like to do is this:

   UpdateModel(
        entity,
        new[] {
            entity.GetMemberName(e => e.Name),
            entity.GetMemberName(e => e.UnitPrice),
        }
    );

where entity somehow supplies the <Product> type. If anybody has any better ideas, please feel to comment.