如果我有一个函数委托的表达式,它接受了许多参数:
Expression<Func<int, int, int, bool>> test = (num1, num2, num3) => num1 + num2 == num3;
有没有办法/怎样才能替换其中一个值(比如说num1
为5)并得到等价的表达式:
Expression<Func<int, int, bool>> test = (num2, num3) => 5 + num2 == num3;
编辑:
还需要解决复杂类型,例如:
Expression<Func<Thing, int, int>> test = (thing, num2) => thing.AnIntProp + num2;
答案 0 :(得分:3)
我的回答是使用表达式访问者。 (感谢@Alexei-levenkov指出它)。
我的具体情况的答案与我在问题中使用的简化示例略有不同。但是,为了完整起见,我就是这样做的:
public class ResolveParameterVisitor : ExpressionVisitor
{
private readonly ParameterExpression _param;
private readonly object _value;
public ResolveParameterVisitor(ParameterExpression param, object value)
{
_param = param;
_value = value;
}
public Expression ResolveLocalValues(Expression exp)
{
return Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == _param.Type && node.Name == _param.Name
&& node.Type.IsSimpleType())
{
return Expression.Constant(_value);
}
return base.VisitParameter(node);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
var parameters = node.Parameters.Where(p => p.Name != _param.Name && p.Type != _param.Type).ToList();
return Expression.Lambda(Visit(node.Body), parameters);
}
}
请注意,IsSimpleType是我通过jonothanconway从this gist借来的扩展。
在我的情况下,我想替换复杂类型的使用。 e.g:
Expression<Func<Thing, int, bool>> test = (thing, num) => thing.AnIntProperty == num;
所以我覆盖了VisitMember方法。这仍然是一项正在进行的工作,但看起来像这样:
protected override Expression VisitMember(MemberExpression m)
{
if (m.Expression != null
&& m.Expression.NodeType == ExpressionType.Parameter
&& m.Expression.Type == _param.Type && ((ParameterExpression)m.Expression).Name == _param.Name)
{
object newVal;
if (m.Member is FieldInfo)
newVal = ((FieldInfo)m.Member).GetValue(_value);
else if (m.Member is PropertyInfo)
newVal = ((PropertyInfo)m.Member).GetValue(_value, null);
else
newVal = null;
return Expression.Constant(newVal);
}
return base.VisitMember(m);
}
这只会解析字段或属性。下一步可能是添加对方法的支持(但因为他们自己有params,所以需要更多的工作......)
编辑:上述成员访问者解决方案也不支持将Object本身传递给方法调用。例如(x, thing) => x.DoSomething(thing)
因此也需要进行修改。