The expression tree creates a dictionary with property values ​​for the class

Essentially I am trying to do this with expression trees

var properties = new Dictionary<string, object>();

foreach (var propInfo in objType.GetTypeInfo().GetProperties(BindingFlags.Public))
{
    var name = propInfo.Name;
    var value = propInfo.GetValue(objInstance);

    properties.Add(name, value);
}

return properties;

      

those. create a dictionary of name and value pairs, where name is the property name for objType

and value is the property value for the instance objInstance

ofobjType

Now, the conversion of this expression to expression should be compiled for the delegate, which simply does

Func<T, Dictionary<string, object>> func = i =>
{
    var properties = new Dictionary<string, object>();

    properties.Add("Prop1", (object)i.Prop1);
    properties.Add("Prop2", (object)i.Prop2);
    properties.Add("Prop3", (object)i.Prop3);
    // depending upon the number of properties of T, Add will continue

    return properties;
};

      

I know how to accomplish this, but I'm not sure how to create a local dictionary instance and then use it (and return it) in subsequent expressions?

+3


source to share


2 answers


It should be something like (inline comments):

public static Func<T, Dictionary<string, object>> GetValuesFunc<T>()
{
    Type objType = typeof(T);

    var dict = Expression.Variable(typeof(Dictionary<string, object>));
    var par = Expression.Parameter(typeof(T), "obj");

    var add = typeof(Dictionary<string, object>).GetMethod("Add", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(string), typeof(object) }, null);

    var body = new List<Expression>();
    body.Add(Expression.Assign(dict, Expression.New(typeof(Dictionary<string, object>))));

    var properties = objType.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);

    for (int i = 0; i < properties.Length; i++)
    {
        // Skip write only or indexers
        if (!properties[i].CanRead || properties[i].GetIndexParameters().Length != 0)
        {
            continue;
        }

        var key = Expression.Constant(properties[i].Name);
        var value = Expression.Property(par, properties[i]);
        // Boxing must be done manually... For reference type it isn't a problem casting to object
        var valueAsObject = Expression.Convert(value, typeof(object));
        body.Add(Expression.Call(dict, add, key, valueAsObject));
    }

    // Return value
    body.Add(dict);

    var block = Expression.Block(new[] { dict }, body);

    var lambda = Expression.Lambda<Func<T, Dictionary<string, object>>>(block, par);
    return lambda.Compile();
}

      

use it like:



public class Test
{
    public int A { get; set; }
    public string B { get; set; }
}

      

and

Func<Test, Dictionary<string, object>> fn = GetValuesFunc<Test>();

var obj = new Test
{
    A = 5,
    B = "Foo"
};

var res = fn(obj);

      

+3


source


Do you only need expressions for caching getters unless you know an easier way (for example, somehow dynamically)?



public static Func<T, Dictionary<string, object>> GetToDict<T>(){
    var getters = typeof(T)
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Select(p => {
            var param = Expression.Parameter(typeof(T));
            return new KeyValuePair<PropertyInfo, Func<T, object>>(p, 
                Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.MakeMemberAccess(param, p), typeof(object)), param).Compile());
        })
        .ToList();
    return i => getters.ToDictionary(x => x.Key.Name, x => x.Value(i));
}

      

0


source







All Articles