c# - 动态递归 lambda 表达式

标签 c# asp.net dynamic lambda expression

我想创建动态 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/

相关文章:

c# - ASP.NET C#,需要按两次按钮才能发生某些事情

c# - ASP.NET:如何将文件从数据库发送到打印机?

jquery - 如何像管理面板一样在 Django 中的外键中添加新项目?

c# - 如何通过在运行时按下按钮在 C# 中动态删除组合框?

asp.net - 将 ASP.NET 编译为 64 位

c# - 公开 ExpandoObject 的属性

C#: new file() - 根保存位置在哪里?

c# - 在 C# 中写入 Excel 文件

c# - 如何动态构建 Entity Framework 查询?

c# - Dot Net Core 和 Azure 存储 : Could not load file or assembly System, 版本=4.0.0.0