Выражение LINQ для SubEntity, которое имеет тип List - PullRequest
0 голосов
/ 23 января 2020

Я пытаюсь динамически создавать выражения для механизма правил, и все шло очень хорошо, пока я не попытался разрешить вложенные типы для списка.

  1. Мой пример приложения выдает ошибку приведения W / ниже кода образца:

  2. Кроме того, мне нужно сделать мой RuleEngine logi c generi c таким, чтобы я мог взять List.List

Есть рекомендации?

public class Container
    {
        public string Repository {get;set; } = "TestRepo";
        public List<Shipment> Shipments { get;set;} = new List<Shipment>();
    }
    public class Shipment
    {
        public int OrderNumber { get; set; } 
    }

Вот мой класс правил

 public class RuleEx
    {
        public string MemberName { get; set; }
        public string Operator { get; set; }
        public string TargetValue { get; set; }
    }
Here is my Rule Engine
 public class RuleEngine
    {
        public bool PassesRules<T>(List<RuleEx> rules, T toInspect)
        {
            return this.CompileRules<T>(rules).Invoke(toInspect);
        }
        public Func<T, bool> CompileRule<T>(RuleEx r)
        {
            var paramUser = Expression.Parameter(typeof(T));
            Expression expr = BuildExpr<T>(r, paramUser);

            return Expression.Lambda<Func<T, bool>>(expr, paramUser).Compile();
        }

        public Func<T, bool> CompileRules<T>(IList<RuleEx> rules)
        {
            var paramUser = Expression.Parameter(typeof(T));
            List<Expression> expressions = new List<Expression>();
            foreach (var r in rules)
            {
                expressions.Add(BuildExpr<T>(r, paramUser));
            }
            var expr = AndExpressions(expressions);

            return Expression.Lambda<Func<T, bool>>(expr, paramUser).Compile();
        }

        Expression AndExpressions(IList<Expression> expressions)
        {
            if (expressions.Count == 1)
                return expressions[0];
            Expression exp = Expression.And(expressions[0], expressions[1]);
            for (int i = 2; expressions.Count > i; i++)
            {
                exp = Expression.And(exp, expressions[i]);
            }
            return exp;
        }

        Expression BuildExpr<T>(RuleEx r, ParameterExpression param)
        {
            Expression propExpression;
            Type propType;
            ExpressionType tBinary;
            if (r.MemberName.Contains('.'))
            {
                String[] childProperties = r.MemberName.Split('.');
                var property = typeof(T).GetProperty(childProperties[0]);
                var paramExp = Expression.Parameter(typeof(T), "SomeObject");

                propExpression = Expression.PropertyOrField(param, childProperties[0]);
                for (int i = 1; i < childProperties.Length; i++)
                {
                    property = property.PropertyType.GetProperty(childProperties[i]);
                    propExpression = Expression.PropertyOrField(propExpression, childProperties[i]);
                }
                propType = propExpression.Type;
            }
            else
            {
                propExpression = Expression.PropertyOrField(param, r.MemberName);
                propType = propExpression.Type;
            }

            // is the operator a known .NET operator?
            if (ExpressionType.TryParse(r.Operator, out tBinary))
            {
                var right = Expression.Constant(Convert.ChangeType(r.TargetValue, propType));
                // use a binary operation, e.g. 'Equal' -> 'u.Age == 15'
                return Expression.MakeBinary(tBinary, propExpression, right);
            }
            else
            {
                var method = propType.GetMethod(r.Operator);
                var tParam = method.GetParameters()[0].ParameterType;
                var right = Expression.Constant(Convert.ChangeType(r.TargetValue, tParam));
                // use a method call, e.g. 'Contains' -> 'u.Tags.Contains(some_tag)'
                return Expression.Call(propExpression, method, right);
            }
        }

    }

Program.CS

var Shipments = new List<Shipment>()
            {
                new Shipment(){ OrderNumber = 555 },
                new Shipment(){ OrderNumber = 200 },
                new Shipment(){ OrderNumber = 200 }
            };


            Container container = new Container()
            {
                Repository = "TestRepo",
                Shipments = Shipments
            };

            RuleEngine mr = new RuleEngine();
            var rules = new List<RuleEx>() { new RuleEx() { MemberName = "Shipment.OrderNumber", Operator = "LessThanOrEqual", TargetValue = 250 } };
            var pases = mr.PassesRules<Container>(rules, container);
...