how to create expression tree / lambda for a deep property from a string

后端 未结 5 1272
渐次进展
渐次进展 2020-12-13 16:07

Given a string: \"Person.Address.Postcode\" I want to be able to get/set this postcode property on an instance of Person. How can I do this? My idea was to split the string

5条回答
  •  执笔经年
    2020-12-13 17:03

    It sounds like you're sorted with regular reflection, but for info, the code to build an expression for nested properties would be very similar to this order-by code.

    Note that to set a value, you need to use GetSetMethod() on the property and invoke that - there is no inbuilt expression for assigning values after construction (although it is supported in 4.0).

    (edit) like so:

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    class Foo
    {
        public Foo() { Bar = new Bar(); }
        public Bar Bar { get; private set; }
    }
    class Bar
    {
        public string Name {get;set;}
    }
    static class Program
    {
        static void Main()
        {
            Foo foo = new Foo();
            var setValue = BuildSet("Bar.Name");
            var getValue = BuildGet("Bar.Name");
            setValue(foo, "abc");
            Console.WriteLine(getValue(foo));        
        }
        static Action BuildSet(string property)
        {
            string[] props = property.Split('.');
            Type type = typeof(T);
            ParameterExpression arg = Expression.Parameter(type, "x");
            ParameterExpression valArg = Expression.Parameter(typeof(TValue), "val");
            Expression expr = arg;
            foreach (string prop in props.Take(props.Length - 1))
            {
                // use reflection (not ComponentModel) to mirror LINQ 
                PropertyInfo pi = type.GetProperty(prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }
            // final property set...
            PropertyInfo finalProp = type.GetProperty(props.Last());
            MethodInfo setter = finalProp.GetSetMethod();
            expr = Expression.Call(expr, setter, valArg);
            return Expression.Lambda>(expr, arg, valArg).Compile();        
    
        }
        static Func BuildGet(string property)
        {
            string[] props = property.Split('.');
            Type type = typeof(T);
            ParameterExpression arg = Expression.Parameter(type, "x");
            Expression expr = arg;
            foreach (string prop in props)
            {
                // use reflection (not ComponentModel) to mirror LINQ 
                PropertyInfo pi = type.GetProperty(prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }
            return Expression.Lambda>(expr, arg).Compile();
        }
    }
    

提交回复
热议问题