我尝试创建一个函数来比较原始值和更新值,并将原始设置为更新的(如果不同)。该功能做得更多,所以我简化为专注于主题:
public void Match<T>(Expression<Func<object>> original, Expression<Func<object>> updated)
{
var mex = original.Body as MemberExpression;
var funcOriginal = original.Compile();
var funcUpdated = updated.Compile();
var valueOriginal = funcOriginal();
var valueUpdated = funcUpdated();
if (valueOriginal != valueUpdated)
{
var info = mex.Member as PropertyInfo;
var target = ???; //How to get the original.TestProperty here?
info.SetValue(target, valueUpdated);
}
}
我想这样打电话:
manager.Match<TestClass>(() => original.TestProperty, () => updated.TestProperty);
答案 0 :(得分:4)
您的成员信息的Expression
属性表示从中获取属性的变量。您只需调用它来将其评估为值。
public static void Match<T>(Expression<Func<T>> original,
Expression<Func<T>> updated)
{
var mex = original.Body as MemberExpression;
var valueOriginal = original.Compile()();
var valueUpdated = updated.Compile()();
if (!object.Equals(valueOriginal, valueUpdated))
{
var info = mex.Member as PropertyInfo;
var target = Expression.Lambda(mex.Expression).Compile().DynamicInvoke();
info.SetValue(target, valueUpdated);
}
}
当然,如果这个类型是一个值类型,那么你将通过调用这个表达式创建的是该值的副本,你最终会改变副本,但只要它是一个引用类型你将要复制引用,实际上对象将会发生变异。
你可以采取另一种截然不同的途径。您可以简单地创建一个表达式来表示您对该表达式赋予的值,而不是尝试评估可以将此属性赋值给的变量。如果从值类型访问属性,此代码甚至可以工作,因为它实际上是在改变变量,而不是获取该变量的值并将其变异。
public static void Match<T>(Expression<Func<T>> original,
Expression<Func<T>> updated)
{
var mex = original.Body as MemberExpression;
var valueOriginal = original.Compile()();
var valueUpdated = updated.Compile()();
if (!object.Equals(valueOriginal, valueUpdated))
{
var body = Expression.Assign(
Expression.MakeMemberAccess(mex.Expression, mex.Member),
updated.Body);
Expression.Lambda<Action>(body).Compile().Invoke();
}
}
尽管使方法具有通用性,但您实际上并没有将通用参数用于两个函数的结果类型。
答案 1 :(得分:0)
如果您想要类型安全,可以传递原始
public void Match<TSource, TType>(TSource dest, Expression<Func<TSource, TType>> original, TType updateValue)
{
var originalValue = original.Compile()(dest);
if (!updateValue.Equals(originalValue))
{
// get prop name from expression
var prop = original.GetMemberInfo().Name;
typeof(TSource).GetProperty(prop).SetValue(dest, updateValue);
}
}
//helper class to get propinfo from expression
public static class ExpressionExtensions
{
public static MemberInfo GetMemberInfo(this Expression expression)
{
var lambda = (LambdaExpression) expression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = (UnaryExpression) lambda.Body;
memberExpression = (MemberExpression) unaryExpression.Operand;
}
else
memberExpression = (MemberExpression) lambda.Body;
return memberExpression.Member;
}
}
像
一样使用它manager.Match(original, o=>o.TestProperty, updated.TestProperty);
我没有对它进行测试,但是应该可以工作或者让你接近。