C# - 使用lambda将表达式参数转换为另一个表达式?

时间:2017-06-07 15:51:58

标签: c# lambda expression

作为WPF应用程序的一部分,我正在构建表达式树并生成谓词以用作过滤器。代码看起来像这样:

public Expression BuildExpression(Expression parameter, string value)
{
    MethodInfo toStringMethod = new Func<Object, string>((a) => a.ToString()).Method;
    Expression lhs = Expression.Call(parameter, toStringMethod );
    ConstantExpression rhs = Expression.Constant(value);
    BinaryExpression result = Expression.Equal(lhs, rhs);
    return result;
}

这是因为参数是未知类型的表达式 - 它可能是int,string,Guid或其他任何东西。问题在于,如果没有大量的评论,很难理解这里发生了什么。我真的很想在这里使用lambda:

return parameter => parameter.ToString() == value;

问题是这不能按预期工作 - 结果委托会在Expression上调用ToString()而不是表达式的。如果有帮助,参数是一个MemberExpression。

1 个答案:

答案 0 :(得分:0)

我能够用很少的额外代码找到一种方法来做到这一点。这个解决方案的主要灵感来自Mark Gravell对Combining two expressions (Expression<Func<T, bool>>)

的回答
  

从.net 4.0开始。有ExpressionVistor类   允许您构建EF安全的表达式。

Expression<TDelegate>派生自LambdaExpression(如果您有兴趣了解这些实际工作的更多信息,我建议您查看“LINQ - Expression Tree Visualizer”示例,该示例目前位于https://code.msdn.microsoft.com/LINQ-Expression-Tree-47608cb5 )。这行代码:

Expression<Predicate<Object>> e1 = a => a.ToString() == "foo";

使用单个ParameterExpression创建LambdaExpression(Type:Object,ReturnType:Boolean,Body:(LogicalBinaryExpression))。使用自定义ExpressionVisitor,我们可以修改Lambda的主体以创建与我之前的代码相同的结果:

public class ReplaceExpressionVisitor
    : ExpressionVisitor
{
    private readonly Expression _oldValue;
    private readonly Expression _newValue;

    public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
    {
        _oldValue = oldValue;
        _newValue = newValue;
    }

    public override Expression Visit(Expression node)
    {
        if (node == _oldValue)
            return _newValue;
        return base.Visit(node);
    }
}

// Elsewhere...
public Expression BuildExpression(Expression parameter, string value)
{
    Expression<Predicate<Object>> e1 = a => a.ToString() == value;
    return (new ReplaceExpressionVisitor(e1.Parameters[0], parameter)).Visit(e1.Body);
}

绝对可以进行进一步的清理(提供静态和/或扩展方法),但这符合我的需求。