static void

Static Reflection of property names

From .Net 3.5 you can use Expressions for "static reflection". You can get compile-time checking when you refer to properties by name. The most widely quoted example is Fluent NHibernate, and this small helper steals from it too.

Example

//property names as strings- look out for typos
DropDownList1.DataTextField = "Name";
DropDownList1.DataValueField = "Id";
//expression gives intellisense and strong typing
DropDownList1.DataTextField = Property.Name<Person>(x => x.Name);
DropDownList1.DataValueField = Property.Name<Person>(x => x.Id);

Code

using System;
using System.Linq.Expressions;
using System.Reflection;
 
namespace Library.Reflection
{
    /// <summary>
    /// Get the string name and type of a property or field. Eg <c>string name = Property.Name&lt;string&gt;(x =&gt; x.Length);</c>
    /// </summary>
    public static class Property
    {
        /// <summary>
        /// Gets the type for the specified entity property or field. Eg <c>string name = Property.Name&lt;string&gt;(x =&gt; x.Length);</c>
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity (interface or class).</typeparam>
        /// <param name="expression">The expression returning the entity property, in the form x =&gt; x.Id</param>
        /// <returns>The name of the property as a string</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static string Name<TEntity>(Expression<Func<TEntity, object>> expression)
        {
            var memberExpression = GetMemberExpression(expression);
 
            var propertyInfo = memberExpression.Member as MemberInfo;
            if (propertyInfo != null)
                return propertyInfo.Name;
            //unknown
            return null;
        }
 
        /// <summary>
        /// Gets the type for the specified entity property or field. Eg Type&lt;string&gt;(x =&gt; x.Length) == typeof(int)
        /// </summary>
        /// <typeparam name="TEntity">The type of the entity (interface or class).</typeparam>
        /// <param name="expression">The expression returning the entity property, in the form x =&gt; x.Id</param>
        /// <returns>A type.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public static Type Type<TEntity>(Expression<Func<TEntity, object>> expression)
        {
            var memberExpression = GetMemberExpression(expression);
 
            var propertyInfo = memberExpression.Member as PropertyInfo;
            if (propertyInfo != null)
                return propertyInfo.PropertyType;
 
            //not a property, maybe a public field
            var fieldInfo = memberExpression.Member as FieldInfo;
            if (fieldInfo != null)
                return fieldInfo.FieldType;
 
            //unknown
            return typeof(object);
        }
 
        private static MemberExpression GetMemberExpression<TEntity, T>(Expression<Func<TEntity, T>> expression)
        {
            //originally from Fluent NHibernate
            MemberExpression memberExpression = null;
            if (expression.Body.NodeType == ExpressionType.Convert)
            {
                var body = (UnaryExpression)expression.Body;
                memberExpression = body.Operand as MemberExpression;
            }
            else if (expression.Body.NodeType == ExpressionType.MemberAccess)
            {
                memberExpression = expression.Body as MemberExpression;
            }
 
            //runtime exception if not a member
            if (memberExpression == null)
                throw new ArgumentException("Not a property or field", "expression");
 
            return memberExpression;
        }
    }
}