我跟随此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;
}
由于我对表达式完全陌生,我不知道从哪里获取属性名称和值,以及包含我想要检查的值的列表。这些属性和值存储在表达式中的哪个位置?
答案 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)
基本上,您需要处理Method,Object(表示实例方法调用的实例的表达式或静态方法调用的)和Arguments (表示被调用方法的参数的表达式集合)MethodCallExpression类的属性。
专门针对{% for user in users %}
{% if forloop.counter <= 4 %}
<a href="#">{{ user.website }}</a>
{% endif %}
{% endfor %}
,您需要避免(或在需要时以不同方式处理)Contains
方法,并处理string.Contains
方法(如static
以及实例方法像Enumerable.Contains
,ICollection<T>.Contains
等。为了获得列表值(如果可能),你必须找到某种常量表达式。
以下是一个示例:
List<T>.Contains