PropertyInfo selector using Lambda expressions

Considering the Type.GetProperty() method provided in System.Reflection, it takes a string parameter. If we are writing frameworks, this is often fine as the hard coded strings are usually self contained, and won’t be exposed to developers that users our framework. While what if we need to provide a function for those developers that uses our library to specify a property? In this case, strings may not be the best solution. Simply taking one scenario, if the property is refactored to a new name, and the string isn’t changed, then the property won’t be found using the old name.

The following example is trying to provide a way to get a PropertyInfo based on an expression. Comparing to directly using Type.GetProperty() method, this type safe, and the expression will change when the property is refactored.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
 
namespace Demo
{
    public static class PropertySelector
    {
        public static PropertyInfo GetPropertyInfo<T>(this T obj, Expression<Func<T, object>> selector)
        {
            if (selector.NodeType != ExpressionType.Lambda)
            {
                throw new ArgumentException("Selector must be lambda expression", "selector");
            }
 
            var lambda = (LambdaExpression) selector;
 
            var memberExpression = ExtractMemberExpression(lambda.Body);
 
            if (memberExpression == null)
            {
                throw new ArgumentException("Selector must be member access expression", "selector");
            }
 
            if (memberExpression.Member.DeclaringType == null)
            {
                throw new InvalidOperationException("Property does not have declaring type");
            }
 
            return memberExpression.Member.DeclaringType.GetProperty(memberExpression.Member.Name);
        }
 
        private static MemberExpression ExtractMemberExpression(Expression expression)
        {
            if (expression.NodeType == ExpressionType.MemberAccess)
            {
                return ((MemberExpression) expression);
            }
 
            if (expression.NodeType == ExpressionType.Convert)
            {
                var operand = ((UnaryExpression) expression).Operand;
                return ExtractMemberExpression(operand);
            }
 
            return null;
        }
    }
}

Example of usage as below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
 
namespace Demo
{
    class Program
    {
        private class InnerClass
        {
            public string Name { get; set; }
        }
 
        public string Name { get; set; }
 
        InnerClass Inner { get; set; }
 
        private static void Main(string[] args)
        {
            var p = new Program();
 
            PrintProperty(p.GetPropertyInfo(item => item.Name));
            PrintProperty(p.GetPropertyInfo(item => item.Inner.Name));
        }
 
        private static void PrintProperty(PropertyInfo propertyInfo)
        {
            Console.WriteLine(propertyInfo.PropertyType + " " + propertyInfo.DeclaringType + "." + propertyInfo.Name);
        }
    }
}

Which gives the following result:

System.String Demo.Program.Name 
System.String Demo.Program+InnerClass.Name

One thought on “PropertyInfo selector using Lambda expressions”

  1. Everything is very open with a clear clarification of
    the challenges. It was really informative. Your website is
    very useful. Thank you for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *