简体   繁体   English

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

[英]C# - Expression parameter into another Expression using lambda?

As part of a WPF application I'm building an expression tree and generating a Predicate to use as a filter. 作为WPF应用程序的一部分,我正在构建一个表达式树并生成一个谓词以用作过滤器。 The code looks something like this: 代码看起来像这样:

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

This is because the parameter is an Expression of unknown type - it might be an int, string, Guid or anything else. 这是因为参数是未知类型的表达式-它可能是int,字符串,Guid或其他任何值。 The problem is that it's difficult to understand what's going on here without copious comments. 问题在于,如果没有大量评论,很难理解这里发生的事情。 I'd really like to use a lambda here: 我真的很想在这里使用lambda:

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

The problem is that this doesn't work as intended - the resulting delegate would call ToString() on the Expression instead of the value of the expression. 问题在于这不能按预期方式工作-生成的委托将在Expression上调用ToString()而不是表达式的 If it helps, parameter is a MemberExpression. 如果有帮助,则参数为MemberExpression。

I was able to find a way to do this with very little extra code. 我能够找到一种方法,只需很少的额外代码。 The main inspiration for this solution was Mark Gravell's answer to Combining two expressions (Expression<Func<T, bool>>) 该解决方案的主要灵感来自Mark Gravell对组合两个表达式(Expression <Func <T,bool >>)的回答。

Starting from .net 4.0. 从.net 4.0开始。 There is the ExpressionVistor class which allows you to build expressions that are EF safe. 有ExpressionVistor类,它允许您构建EF安全的表达式。

Expression<TDelegate> is derived from LambdaExpression (if you're interested in learning more about how these actually work I encourage you to check out the "LINQ - Expression Tree Visualizer" sample, currently located at https://code.msdn.microsoft.com/LINQ-Expression-Tree-47608cb5 ). Expression<TDelegate>是从LambdaExpression派生的(如果您有兴趣了解有关它们实际工作方式的更多信息,建议您查看“ LINQ-Expression Tree Visualizer”示例,该示例当前位于https://code.msdn.microsoft .com / LINQ-Expression-Tree-47608cb5 )。 This line of code: 这行代码:

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

Creates a LambdaExpression with a single ParameterExpression(Type: Object, ReturnType: Boolean, Body:(LogicalBinaryExpression)). 使用单个ParameterExpression(Type:Object,ReturnType:Boolean,Body:(LogicalBinaryExpression))创建一个LambdaExpression。 Using a custom ExpressionVisitor we can modify the body of the Lambda to create the same result as my previous code: 使用自定义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);
}

Further cleanup is definitely possible (provide a static and/or extension method) but this meets my needs. 肯定可以进行进一步的清理(提供静态和/或扩展方法),但这可以满足我的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM