动态递归 lambda 表达式
我想创建动态 lambda 表达式,以便可以使用一组过滤参数来过滤列表。这就是我到目前为止所拥有的:
表达式是使用下面的方法构建的,其中 T 是
public static Expression<Func<T, bool>> GetExpression<T>(IList<DynamicFilter> filters)
{
if (filters.Count == 0)
return null;
ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;
if (filters.Count == 1)
exp = GetExpression<T>(param, filters[0]);
[...]
return Expression.Lambda<Func<T, bool>>(exp, param);
}
private static Expression GetExpression<T>(ParameterExpression param, DynamicFilter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
ConstantExpression constant = Expression.Constant(filter.Value);
[...]
return Expression.Call(member, filterMethod, constant);
}
我然后调用的
List<Example> list = ...;
var deleg = ExpressionBuilder.GetExpression<Example>(dynFiltersList).Compile();
list = list.Where(deleg).ToList();
列表的对象类型这对于仅包含简单类型的对象来说就像预期的那样,但如果里面有复杂类型,代码不再起作用。例如,假设我在 Example 类中有一个自定义类型 Field 的成员,并且 Field 有一个字符串属性 Value。如果 filter.PropertyName
是“Field0”(Field 类型),则代码可以正常工作,但如果我有“Field0.Value”,我会收到一个明显的错误,指出没有属性在类示例中名为“Field0.Value”。
我尝试修改表达式构建方法,如下所示:
MemberExpression member = null;
if (filter.PropertyName.Contains('.'))
{
string[] props = filter.PropertyName.Split('.');
ParameterExpression param1 = Expression.Parameter(typeof(T).GetProperty(props[0]).PropertyType, "t1");
member = Expression.Property(param1, props[0]);
}
else
{
member = Expression.Property(param, filter.PropertyName);
}
但随后在编译表达式时出现 Lambda 参数不在范围内 错误。我有点明白为什么会出现此错误,但我不知道如何使其工作。
底线是我需要在形成 MemberExpression 时使表达式构建方法递归工作。我最终需要获得一个 list = list.Where(deleg).ToList();
,它可以转换为这样的 list = list.Where(obj => obj.Field0.Value == 'something').ToList();
我刚刚开始使用表达式,所以我在这方面并不太了解,但任何帮助将不胜感激。
谢谢
I want to create dynamic lambda expressions so that I can filter a list using a set of filtering parameters. This is what I have so far:
The expression is built using the methods bellow, where T is the object type of the list
public static Expression<Func<T, bool>> GetExpression<T>(IList<DynamicFilter> filters)
{
if (filters.Count == 0)
return null;
ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;
if (filters.Count == 1)
exp = GetExpression<T>(param, filters[0]);
[...]
return Expression.Lambda<Func<T, bool>>(exp, param);
}
private static Expression GetExpression<T>(ParameterExpression param, DynamicFilter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
ConstantExpression constant = Expression.Constant(filter.Value);
[...]
return Expression.Call(member, filterMethod, constant);
}
I then call
List<Example> list = ...;
var deleg = ExpressionBuilder.GetExpression<Example>(dynFiltersList).Compile();
list = list.Where(deleg).ToList();
This works just as expected with an object that contains only simple types, but if there are complex types inside, the code doesn't work anymore. For example, let's say I have a member of custom type Field inside the Example class and Field has a string property Value. If filter.PropertyName
would be 'Field0' (of type Field), the code would work just fine, but if I have 'Field0.Value' I would get an obvious error stating that there is no property named 'Field0.Value' inside class Example.
I tried modifying the expression building method, like this:
MemberExpression member = null;
if (filter.PropertyName.Contains('.'))
{
string[] props = filter.PropertyName.Split('.');
ParameterExpression param1 = Expression.Parameter(typeof(T).GetProperty(props[0]).PropertyType, "t1");
member = Expression.Property(param1, props[0]);
}
else
{
member = Expression.Property(param, filter.PropertyName);
}
but then I got a Lambda parameter not in scope
error when compiling the expression. I sort of understand why I get this error, but I don't know how to make this work.
Bottom line is I need to make the expression building method work recursively when forming the MemberExpression. I ultimately need to obtain a list = list.Where(deleg).ToList();
that translates to something like this list = list.Where(obj => obj.Field0.Value == 'something').ToList();
I've just started working with expressions so I don't really know too much in this area, but any help would be appreciated.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我意识到这是一篇相当老的帖子,但我遇到了完全相同的问题,并在 Mark Gravell 发布的答案中找到了一些接近的内容 此处。我只是稍微修改了一下以满足我的需求,结果如下:
实现:
I realize this is a fairly old post, but I had the exact same problem and found something close in an answer that Mark Gravell posted here. I just modified it slightly to meet my needs and below is the result:
Implementation:
我正在尝试解决
而不是使用
ExpressionBuilder
,而是使用通用的 Filter 类。首先我们需要上一些课。
然后我们需要一个对象列表。
然后让我们创建几个过滤器并将它们添加到列表中。
最后通过这些过滤器过滤列表
只有“Fafhrd”将出现在
highLevelAndPowerfulSwords
中,而highLevelOrPowerfulSwords
将包含除“Mouse”之外的所有玩家。I'm trying to address
not by using
ExpressionBuilder
but instead by using a generic Filter class.First we need to have some classes.
Then we need a list of objects.
Then let's create a couple of filters and add those to a list.
Finally filter the list by those filters
Only "Fafhrd" will be in
highLevelAndPowerfulSwords
andhighLevelOrPowerfulSwords
will contain all players but "Mouse".看一下 ExpressionVisitor,如下所述:替换参数表达式主体中的名称
Have a look at ExpressionVisitor as described here: Replacing the parameter name in the Body of an Expression
您可以为过滤器中的每个元素生成一个表达式,并使用以下方法将它们组合成一个表达式:
You could generate an expression for each element in filter and combine them into one single expression using the methods below: