我想创建动态 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 有一个字符串属性值。如果 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 parameter not in scope
错误。我有点理解为什么会收到此错误,但我不知道如何让它工作。
底线是在形成 MemberExpression 时,我需要使表达式构建方法递归工作。我最终需要获得一个 list = list.Where(deleg).ToList();
转换成这样的东西 list = list.Where(obj => obj.Field0.Value = = '某物').ToList();
我刚刚开始使用表达式,所以我对这方面了解不多,但如有任何帮助,我们将不胜感激。
谢谢
最佳答案
我意识到这是一个相当古老的帖子,但我遇到了完全相同的问题,并在 Mark Gravell 发布的答案中找到了一些相似的东西 here .我只是稍微修改了一下以满足我的需要,结果如下:
private Expression GetDeepProperty(Expression parameter, string property)
{
var props = property.Split('.');
var type = parameter.Type;
var expr = parameter;
foreach (var prop in props)
{
var pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
return expr;
}
实现:
var method = typeof (string).GetMethod("Contains", new Type[] {typeof (string)}, null);
var lambdaParameter = Expression.Parameter(typeof(TEntity), "te");
var filterExpression = Expression.Lambda<Func<TEntity, bool>> (
filters.Select(filter => Expression.Call(GetDeepProperty(lambdaParameter, filter.Property),
method,
Expression.Constant(filter.Value))).
Where(exp => exp != null).
Cast<Expression>().
ToList().
Aggregate(Expression.Or), lambdaParameter);
关于c# - 动态递归 lambda 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6123464/