Если возникает необходимость одинаковой обработки присвоения значения свойству объекта, то можно воспользоваться лямбда выражениями.
Такая задача может возникнуть при проверке или обработке значений, логгировании присвоения и т.д.
Простейший метод, который не учитывает присвоение свойствам вложенных объектов, будет такой:
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/
Добавить комментарий