通过迭代对象属性生成动态 LINQ 表达式

Generate Dynamic LINQ Expression By Iterating object properties

我正在尝试遍历对象中的所有属性,包括嵌套对象和集合中的对象,以生成 LINQ 表达式。我的类的结构如下:

public class Rule
{
    public string label { get; set; }
    public string field { get; set; }
    public string @operator { get; set; }
    public string type { get; set; }
    public string value { get; set; }
    public string condition { get; set; }
    public List<Rule> rules { get; set; }
}
public class QueryBuilder
{

    public string condition { get; set; }
    public List<Rule> rules { get; set; }

}

下面是上述实体映射的示例JSON

{
"condition": "and",
"rules": [
    {
        "condition": "or",
        "rules": [
            {
                "label": "PaymentMode",
                "field": "PaymentMode",
                "operator": "equal",
                "type": "string",
                "value": "Cash"
            },
            {
                "label": "TransactionType",
                "field": "TransactionType",
                "operator": "equal",
                "type": "string",
                "value": "expensive"
            }
        ]
    },
    {
        "condition": "or",
        "rules": [
            {
                "label": "Date",
                "field": "Date",
                "operator": "equal",
                "type": "date",
                "value": "4/15/21"
            },
            {
                "label": "Date",
                "field": "Date",
                "operator": "equal",
                "type": "date",
                "value": "4/15/21"
            }
        ]
    }
]
}

上面的 json 将在一个层次结构中。用户可以 select 任意数量的 AND 或 OR 条件。需要在递归循环中制作波纹管表达式

var constant = Expression.Constant("Jhon");
              var property = Expression.Property(paramExpr,"FirstName");
              expression = Expression.Equal(property, constant);

              constant = Expression.Constant("Ram");
              property = Expression.Property(paramExpr, "LastName");
              var expression2 = Expression.Equal(property, constant);
              expression = Expression.Or(expression, expression2);

如何使用上述结构进行递归循环。

应该这样做:

    public Expression BuildExpression(ParameterExpression paramExpr, Rule rule)
    {
        if (rule.condition != null)
        {
            if (rule.condition != "or" && rule.condition != "and")
                throw new Exception($"Condition [{rule.condition}] is invalid.");

            if (rule.rules == null || rule.rules.Count < 2)
                throw new Exception($"Cannot create [{rule.condition}] expression.");

            IList<Expression> expressions = rule.rules
                .Select(rule => BuildExpression(paramExpr, rule))
                .ToList();

            if (rule.condition == "or")
                return JoinExpressions(expressions, (left, right) => Expression.OrElse(left, right));
            else
                return JoinExpressions(expressions, (left, right) => Expression.AndAlso(left, right));
        }
        else
        {
            Expression constant = Expression.Constant(rule.value);
            Expression property = Expression.Property(paramExpr, rule.field);

            // added to allow any value to be included.
            if (rule.value == "ANY")
            {
                Type type = GetType(rule.type);
                if (!type.IsPrimitive)
                {
                    constant = Expression.Constant(null, type);

                    switch (rule.@operator)
                    {
                        case "equal": return Expression.NotEqual(property, constant);
                        case "notequal": return Expression.Equal(property, constant);
                        default:
                            throw new Exception($"Operator [{rule.@operator}] is invalid for ANY filter. Use only equal or notequal.");
                    }
                }

                constant = property;
            }

            switch (rule.@operator)
            {
                case "equal": return Expression.Equal(property, constant);
                case "notequal": return Expression.NotEqual(property, constant);
                case "greaterthan": return Expression.GreaterThan(property, constant);
                case "greaterthanorequal": return Expression.GreaterThanOrEqual(property, constant);
                case "lessthan": return Expression.LessThan(property, constant);
                case "lessthanorequal": return Expression.LessThanOrEqual(property, constant);
                default:
                    throw new Exception($"Operator [{rule.@operator}] is invalid.");
            }
        }
    }

    public Expression JoinExpressions(IList<Expression> expressions, Func<Expression, Expression, Expression> join)
    {
        Expression andExpression = null;

        foreach (Expression expression in expressions)
        {
            if (andExpression == null)
                andExpression = expression;
            else
                andExpression = join(andExpression, expression);
        }

        return andExpression;
    }

    public static Type GetType(string typeName)
    {
        switch (typeName)
        {
            case "string": return typeof(string);
            ... add any others.
            default:
                throw new Exception($"Type [{typeName}] is invalid.");
        }
    }