首页 文章

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

提问于
浏览
0

作为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

    我能够用很少的额外代码找到一种方法来做到这一点 . 这个解决方案的主要灵感来自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);
    }
    

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

相关问题