Donn Felker

Not A Subscriber?

Join thousands of people who build and refuse to get left behind. One message a week on building, using AI as an accelerator, and staying sharp in the new AI frontier.

Receive one free message a week

February 10, 2009 Donn Felker

Using Expressions and Func as a Reflection Tool

I’m using Castle Active Record for a project that I’m on and I constantly find myself having to provide column names when creating queries through the ActiveRecordMediator object. Here’s an example:

ActiveRecordMediator<Customer>.FindOne(Expression.Eq("FirstName", "Bob"));

The column name “FirstName” is not strongly typed. If I change that name (or anyone else does) and they don’t use a tool like ReSharper they might run into some issues.

So I poked around a bit and found a few examples of what I was trying to do and created my own strongly typed version with this class:

/// <summary>
/// Returns the name of a property via an expression.
/// </summary>
/// <typeparam name="TypeToParsePropertiesFrom">The type to parse properties from.</typeparam>
public interface IPropertyNameResolver<TypeToParsePropertiesFrom>
{
/// <summary>
/// Parses a property from the given type.
/// </summary>
/// <typeparam name="PropertyToParse">The property to parse.</typeparam>
/// <param name="property">The property.</param>
/// <returns>The property name.</returns>
string ResolvePropertyName<PropertyToParse>(Expression<Func<TypeToParsePropertiesFrom, PropertyToParse>> property);
}
/// <summary>
/// Class responsible for parsing a property name.
/// </summary>
/// <typeparam name="TypeToParsePropertiesFrom">The type to parse properties from.</typeparam>
public class PropertyNameResolver<TypeToParsePropertiesFrom> : IPropertyNameResolver<TypeToParsePropertiesFrom>
{
public string ResolvePropertyName<PropertyToParse>(Expression<Func<TypeToParsePropertiesFrom, PropertyToParse>> property)
{
//
// If the expression body was x.FirstName, it would return a string "x.FirstName".
//
var fullPropertyName = property.Body.ToString();
//
// Parse the index of the period and get the propertyName after that.
// therefore x.FirstName would return "FirstName"
//
return fullPropertyName.Substring(fullPropertyName.IndexOf(".") + 1);
}
}

Usage:

To get a property name using this expression you will need to use a Lambda. Check it out:

IPropertyNameResolver<Customer> customerResolver =
new PropertyNameResolver<Customer>();
var propertyName = customerResolver.ResolvePropertyName(x => x.FirstName);
Assert.That(propertyName, Is.EqualTo("FirstName"));

The only real con is that I have to create an instance of that generic class to do this. But … the good thing is that its strongly typed.