Setting an object property using lambda expressions

    If there is a need for the same processing of assigning a value to a property of an object, then lambda expressions can be used. Such a task may arise when checking or processing values, assignment logging, etc.

    The simplest method, which does not take into account the assignment to the properties of nested objects, will be this:

        public static class ObjectHelper
        {
            public static void Set(this T obj, Expression> property, TProp value)
            {
                if (obj == null) throw new ArgumentNullException("obj");
                if (property == null) throw new ArgumentNullException("property");
                var memberExpression = (MemberExpression) property.Body;
                var targetPropertyInfo = (PropertyInfo) memberExpression.Member;
                // здесь можно дополнительно обработать obj или value согласно бизнес логике
                targetPropertyInfo.SetValue(obj, value);
            }
        }
    

    This will only work for assigning a property to the object itself, but not to the property of the nested object. I.e:

                myObject.Set(x => x.MyProperty, "bla-bla-bla"); // РАБОТАЕТ
                myObject.Set(x => x.MyProperty.InnerProperty, "bla-bla-bla"); // НЕ РАБОТАЕТ
    

    It does not work, because the assignment in this case does not go to the object in myObject.MyProperty, but to the object myObject.
    (Moreover, if the types of MyProperty and myObject are the same, an exception will not be thrown, and there will be a hidden error in the program!)

    In order to work for the properties of nested objects, you need to go through the expression tree and get the desired object, the property of which will be assigned a value :

        public static class ObjectHelper
        {
            public static void Set(this T obj, Expression> property, TProp value)
            {
                if (obj == null) throw new ArgumentNullException("obj");
                if (property == null) throw new ArgumentNullException("property");
                object target = obj;
                var memberExpression = (MemberExpression) property.Body;
                var targetPropertyInfo = (PropertyInfo) memberExpression.Member;
                if (memberExpression.Expression.NodeType != ExpressionType.Parameter)
                {
                    var expressions = new Stack();
                    while (memberExpression.Expression.NodeType != ExpressionType.Parameter)
                    {
                        memberExpression = (MemberExpression)memberExpression.Expression;
                        expressions.Push(memberExpression);
                    }
                    while (expressions.Count > 0)
                    {
                        var expression = expressions.Pop();
                        var propertyInfo = (PropertyInfo)expression.Member;
                        target = propertyInfo.GetValue(target);
                        if (target == null) throw new NullReferenceException(expression.ToString());
                    }
                }
                // здесь можно дополнительно обработать obj, target или value согласно бизнес логике
                targetPropertyInfo.SetValue(target, value);
            }
        }
    

                myObject.Set(x => x.MyProperty, "bla-bla-bla"); // РАБОТАЕТ
                myObject.Set(x => x.MyProperty.InnerProperty, "bla-bla-bla"); // РАБОТАЕТ
    

    Also popular now: