Avoid using property references as string

One thing I try to avoid in my applications, is to express property members and reference as string. For a simple reason, this makes your application less maintainable and harder to refactor.

When using System.Reflection, for example, it is pretty common to enumerate members of a type and use property member as a string, or defining member binding in web apps for example.

When using entity framework include strategies for your queries , as an example, the two following would produce the same output. However one will throw at runtime if you ever change your model. The other simply won’t compile.

String reference

            var strInclude = ctx.Set<Dal.EmployeeAddress>()
                .Include("Address.City.Country")
                .Include("Address.City.SubDivision")
                .Include("Address.StreetDirection")
                .Include("Address.StreetType")
                .Include("Address.SubDivision");

Strongly typed

            var typedInclude = ctx.Set<Dal.EmployeeAddress>()
                .Include(V=>V.Address.City.Country)
                .Include(V => V.Address.City.SubDivision)
                .Include(V => V.Address.StreetDirection)
                .Include(V => V.Address.StreetType)
                .Include(V => V.Address.SubDivision)

 

You can use the same exact concept in your code by replacing your string members with expressions. We then define a simple helper we can reuse everywhere to resolve our navigation paths. Here’s an example of a simple method to resolve a strongly typed property to specify on a MVVM binding :

 

        public static string GetPropertyBinding<T, TProperty>(this T source, Expression<Func<T, TProperty>> path)
        {
            var navPath = path.GetPath();
            return navPath;
        }

        public Demo()
        {
            var employeeAddr = new EmployeeAddress();
            var bindingName = GetPropertyBinding(employeeAddr, V => V.Address.Appartement);
        }

 

All you need is the following extension, and make sure you have the using on top of your code for the extension

using Newsoft.Common.Extensions;

namespace Newsoft.Common.Extensions
{
    public static class ExpressionExtensions
    {
        public static string GetPath<T, TMember>(this Expression<Func<T, TMember>> expr)
        {
            var stack = new Stack<string>();

            MemberExpression me;
            switch (expr.Body.NodeType)
            {
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    var ue = expr.Body as UnaryExpression;
                    me = ((ue != null) ? ue.Operand : null) as MemberExpression;
                    break;
                default:
                    me = expr.Body as MemberExpression;

                    if (me == null && expr.NodeType == ExpressionType.Lambda)
                    {
                        var methCallExpr = expr.Body as MethodCallExpression;

                        var leftOperand = methCallExpr.Arguments[0] as MemberExpression;
                        dynamic rightOperand = methCallExpr.Arguments[1];

                        me = rightOperand.Body as MemberExpression;
                        while (me != null)
                        {
                            stack.Push(me.Member.Name);
                            me = me.Expression as MemberExpression;
                        }

                        stack.Push(leftOperand.Member.Name + "[*]");
                        return string.Join(".", stack.ToArray());
                    }
                    break;
            }

            while (me != null)
            {
                stack.Push(me.Member.Name);
                me = me.Expression as MemberExpression;
            }

            return string.Join(".", stack.ToArray());
        }
    }
}

Submit a Comment

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

Share This