我希望能够使用虚拟方法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东西,然后再将值放入正确的字段的开关”之类的解决方案,因此选择了这种方法。>
答案 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);
}