如何为Contains <t>构建表达式树

时间:2016-04-19 08:42:15

标签: c# linq expression-trees

我跟随此SO answer将lambda表达式转换为部分SQL语法。

但是,我在解析Contains的表达式时遇到问题。我添加了一个方法:

private bool ParseContainsExpression(MethodCallExpression expression)
{
    MemberExpression member = (MemberExpression)expression.Arguments[0];

    var methodInfo = typeof(List<int>).GetMethod("Contains", new Type[] { typeof(int) });

    //TODO check if list contains value

    return false;
}

由于我对表达式完全陌生,我不知道从哪里获取属性名称和值,以及包含我想要检查的值的列表。这些属性和值存储在表达式中的哪个位置?

2 个答案:

答案 0 :(得分:2)

您的实施与示例答案完全不同。您确实需要从ExpressionVisitor继承,以便可以正确解析树。

让我们以此表达式为例:

var myList = new List<string> { "A" };
Expression<Func<string, bool>> a = (s) => myList.Contains(s);
ParseContainsExpression(a.Body as MethodCallExpression);

private bool ParseContainsExpression(MethodCallExpression expression)
{
    expression.Object; //myList
    expression.Arguments[0]; //s    
    return false;
}

但请注意,这些仍然是表达式,它们还不是实际值。您需要调用表达式来获取值。

但是,在我们的案例中,myList实际上是ConstantExpression。所以我们可以这样做:

((expression.Object as MemberExpression).Expression as ConstantExpression).Value; //myList

返回原始列表。请注意,它是 field 访问权限,因为表达式被编译为闭包,它将myList作为闭包类中的字段。正如您所看到的,我们必须对我们正在处理的表达式类型(它是字段访问然后是常量表达式)进行批次假设。您确实需要一个完全成熟的访问者实现来正确地执行此操作(链接的答案描述)

答案 1 :(得分:1)

基本上,您需要处理MethodObject(表示实例方法调用的实例的表达式或静态方法调用的)和Arguments表示被调用方法的参数的表达式集合)MethodCallExpression类的属性。

专门针对{% for user in users %} {% if forloop.counter <= 4 %} <a href="#">{{ user.website }}</a> {% endif %} {% endfor %} ,您需要避免(或在需要时以不同方式处理)Contains方法,并处理string.Contains方法(如static以及实例方法像Enumerable.ContainsICollection<T>.Contains等。为了获得列表值(如果可能),你必须找到某种常量表达式。

以下是一个示例:

List<T>.Contains