2013-07-31 65 views
8

减少的表达。如果我有一个函数委托,它采用像这样的一些参数的表达式:通过输入参数

Expression<Func<int, int, int, bool>> test = (num1, num2, num3) => num1 + num2 == num3; 

是有办法/ I如何可以替换值中的一个(比方说5 num1),并获得相当的表达:

Expression<Func<int, int, bool>> test = (num2, num3) => 5 + num2 == num3; 

编辑:

还需要解决复杂的类型,例如:

Expression<Func<Thing, int, int>> test = (thing, num2) => thing.AnIntProp + num2; 
+0

[C#Linq vs. Currying]可能重复(http://stackoverflow.com/questions/8826266/c-sharp-linq-vs-currying) –

+2

虽然我投票是dup,但这个问题实际上可能是不同的。也许你正在寻找表达式访问者的用法来替代有价值的参数? (沿着[this]的行)(http://stackoverflow.com/questions/11164009/using-a-linq-expressionvisitor-to-replace-primitive-parameters-with-property-ref)) –

+0

不完全。我想与表达式一起工作。我认为它更接近[this](http://stackoverflow.com/questions/11159697/replace-parameter-in-lambda-expression)或[this](http://stackoverflow.com/questions/5631070/currying -expressions-在-C-尖锐) –

回答

2

我的答案是使用表达式访问者。 (感谢@ 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是一个扩展,我从this gist借由jonothanconway。

在我的情况下,我想替换使用复杂类型。例如:

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); 
    } 

这只能解决一个字段或属性。下一步可能是添加对方法的支持(但是因为它们自身有参数,所以需要更多的工作......)

编辑:上述成员访问者解决方案也不支持传递对象本身进入方法调用。例如(x, thing) => x.DoSomething(thing)所以需要修改以做到这一点。