Я хочу иметь возможность обновить свойство 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)) и обновить соответствующее поле в серверном приложении.
Только это поле может быть обновлено, некоторые классы вложены слишком глубоко, чтобы разрешить такие решения, как «просто используйте некоторый идентификатор и переключатель, чтобы затем поместить значение в правильное поле», поэтому был выбран этот подход.





Только что наконец решил сам
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);
}
Вы можете использовать рекурсию, чтобы перейти к обновляемому свойству. Этот код ожидает, что все свойства по пути не будут 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);
}
}
Согласно моим тестам, метод, на который я ответил, в 4 раза быстрее
Это круто, я просто пытаюсь набрать больше репутации :) Я не считал скорость. Я только что проголосовал за ваш ответ
"просто пытаюсь получить более высокую репутацию" Вот! Получил +1, потому что я краду этот код ?
Завтра буду сравнивать скорость, tbh ... даже не думал об этой возможности