使用表达式

时间:2018-09-19 11:35:35

标签: c# reflection expression

要解决的问题

我希望能够使用虚拟方法prop更新属性Update。 为此,我想调用如下方法:

Root obj = /* ... */;
Update(obj, "sub/sub/prop", "foobar");

例如建立一些表达式树来做到这一点?

场景

class Sub2
{
    public string prop { get; set; }
}
class Sub1
{
    public Sub2 sub { get; set; }
}
class Root
{
    public Sub1 sub { get; set; }
}
class Main
{
    //...
    void Update(object obj, string navigation, object newval) { /* magic */ }
}

完整问题

我需要能够序列化某个对象(已经解决,方法头public void Serialize<TProperty>(T obj, Stream s, Expression<Func<T, TProperty>> exp))中的单个字段,并更新服务器应用程序上的相应字段。 仅允许该字段进行更新,有些类嵌套得太深,以至于无法提供“仅使用一些ID东西,然后再将值放入正确的字段的开关”之类的解决方案,因此选择了这种方法。

2 个答案:

答案 0 :(得分:3)

您可以使用递归向下导航至要更新的属性。这段代码期望路径上的所有属性都不是NULL,如果可以为null,那么使用一些检查代码来处理这种情况(抛出异常等)应该很容易。

void Update(object obj, string navigation, object newval)
{
    var firstSlash = navigation.IndexOf("/");
    if (firstSlash < 0)
    {
        obj.GetType().GetProperty(navigation).SetValue(obj, newval);
    }
    else
    {
        var header = navigation.Substring(0, firstSlash);
        var tail = navigation.Substring(firstSlash + 1);
        var subObj = obj.GetType().GetProperty(header).GetValue(obj);
        Update(subObj, tail, newval);
    }
}

答案 1 :(得分:1)

终于做到了,我终于解决了

public void Update1(T obj, string[] input, object newval)
{
    Type t = typeof(T);
    var param1 = Expression.Parameter(t);
    Expression exp = param1;
    foreach (var it in input.Skip(1).Take(input.Length - 2))
    {
        var minfo = t.GetProperty(it).GetGetMethod();
        exp = Expression.Call(exp, minfo);
        t = minfo.ReturnType;
    }
    var lastprop = t.GetProperty(input.Last());
    var minfoset = lastprop.GetSetMethod();
    var variableexp = Expression.Variable(lastprop.PropertyType);
    exp = Expression.Call(exp, minfoset, variableexp);
    var lambda = Expression.Lambda(exp, param1, variableexp);
    lambda.Compile().DynamicInvoke(obj, newval);
}