Установка свойства объекта с использованием лямбда выражений

от автора

Если возникает необходимость одинаковой обработки присвоения значения свойству объекта, то можно воспользоваться лямбда выражениями.
Такая задача может возникнуть при проверке или обработке значений, логгировании присвоения и т.д.

Простейший метод, который не учитывает присвоение свойствам вложенных объектов, будет такой:

    public static class ObjectHelper     {         public static void Set<T, TProp>(this T obj, Expression<Func<T, TProp>> 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);         }     } 

Это сработает только для присвоения свойству самого объекта, но не свойству вложенного объекта.
То есть:

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

Не работает, потому что присвоение в данном случае идет не объекту в myObject.MyProperty, а объекту myObject.
(Причем если типы у MyProperty и myObject одинаковые, то не будет выброшено исключение, и в программе будет скрытая ошибка!)

Для того чтобы сработало и для свойств вложенных объектов, нужно пройтись по дереву выражений и получить нужный объект, свойству которого и будет присваиваться значение:

    public static class ObjectHelper     {         public static void Set<T, TProp>(this T obj, Expression<Func<T, TProp>> 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<MemberExpression>();                  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"); // РАБОТАЕТ 

ссылка на оригинал статьи http://habrahabr.ru/post/259567/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *