예제 #1
0
        private void DoTest <T1, T2>(Expression <Func <T1, T2> > exp, T1 data, string expected)
        {
            ParameterExpression[] currentIndexes;
            var body     = new LinqEliminator().Eliminate(exp.Body, out currentIndexes);
            var paths    = ExpressionPathsBuilder.BuildPaths(exp.Body, currentIndexes);
            var resolved = Expression.Block(currentIndexes, new[]
            {
                body,
                paths
            });

            ParameterExpression[] parameters           = resolved.ExtractParameters();
            Expression <Func <T1, string[][]> > lambda = Expression.Lambda <Func <T1, string[][]> >(resolved, parameters);

            Assert.AreEqual(expected, string.Join(".", LambdaCompiler.Compile(lambda, CompilerOptions.All) /*.Compile()*/ (data)[0]));
        }
            private static void BuildNodeValidator(IPathFormatter pathFormatter, Expression path, List <MutatorConfiguration> mutators, ModelConfigurationNode root, List <KeyValuePair <Expression, Expression> > aliases, Dictionary <ParameterExpression, ExpressionPathsBuilder.SinglePaths> paths, ParameterExpression result, Type treeRootType, ParameterExpression priority, List <Expression> validationResults)
            {
                if (mutators.All(mutator => !(mutator is ValidatorConfiguration)))
                {
                    return;
                }
                Expression isDisabled = null;

                foreach (var mutator in mutators)
                {
                    var disableIfConfiguration = mutator as DisableIfConfiguration;
                    if (disableIfConfiguration == null)
                    {
                        continue;
                    }
                    CheckDependencies(root, disableIfConfiguration);
                    var current = disableIfConfiguration.GetCondition(aliases);
                    if (current != null)
                    {
                        isDisabled = isDisabled == null ? current : Expression.OrElse(current, isDisabled);
                    }
                }

                var firstAlias = new List <KeyValuePair <Expression, Expression> > {
                    aliases.First()
                };
                var aliasesInTermsOfFirst = aliases.Count > 1 ? aliases.Skip(1).ToList() : new List <KeyValuePair <Expression, Expression> >();

                aliasesInTermsOfFirst = aliasesInTermsOfFirst.Select(pair => new KeyValuePair <Expression, Expression>(pair.Key, pair.Value.ResolveAliases(firstAlias))).ToList();

                //var eachesResolver = new EachesResolver(new int[aliasesInTermsOfFirst.Count / 2].Select((x, i) => aliasesInTermsOfFirst[i * 2 + 1].Key).ToArray());

                // Replace LINQ methods with cycles to obtain indexes
                //var resolvedPath = eachesResolver.Visit(path.ResolveAliases(firstAlias));
                var        currentPath          = path.ResolveAliases(aliases);
                var        value                = Expression.Parameter(typeof(object));
                Expression valueAssignment      = Expression.Assign(value, Expression.Convert(new LinqEliminator().Eliminate(currentPath, out var currentIndexes), typeof(object)));
                var        currentPaths         = ExpressionPathsBuilder.BuildPaths(currentPath, currentIndexes, paths);
                var        resolvedArrayIndexes = currentPaths.paths.Select(p => new ResolvedArrayIndexes {
                    path = p
                }).ToArray();

                var chains = path.CutToChains(true, true).GroupBy(exp => new ExpressionWrapper(exp, false)).Select(grouping => grouping.Key.Expression.ResolveAliases(firstAlias)).ToArray();
                //Expression cutChains = Expression.NewArrayInit(typeof(string[]), chains.Select(expression => eachesResolver.Visit(expression).ResolveArrayIndexes()));

                Expression formattedChains = null;

                if (pathFormatter != null)
                {
                    formattedChains = pathFormatter.GetFormattedPath(chains);
                    if (formattedChains != null)
                    {
                        formattedChains = formattedChains.ResolveAliases(aliasesInTermsOfFirst);
                    }
                }

                if (formattedChains == null)
                {
                    // Default path formatting - simply list all the paths along the object tree
                    if (!(pathFormatter is PathFormatterWrapper))
                    {
                        formattedChains = FormatPaths(currentPaths);
                    }
                    else
                    {
                        formattedChains = Expression.Constant(null, typeof(MultiLanguagePathText));
                    }
                }

                var localResults = new List <Expression> {
                    valueAssignment
                };

                foreach (var validator in mutators.Where(mutator => mutator is ValidatorConfiguration).Cast <ValidatorConfiguration>())
                {
                    CheckDependencies(root, validator);
                    var appliedValidator = validator.Apply(root.ConfiguratorType, aliases).EliminateLinq();
                    if (appliedValidator == null)
                    {
                        continue;
                    }
                    var currentValidationResult = Expression.Variable(typeof(ValidationResult));
                    if (validator.Priority < 0)
                    {
                        throw new PriorityOutOfRangeException("Validator's priority cannot be less than zero");
                    }
                    if (validator.Priority >= PriorityShift)
                    {
                        throw new PriorityOutOfRangeException("Validator's priority must be less than " + PriorityShift);
                    }
                    var        validatorPriority = Expression.Constant(validator.Priority);
                    Expression currentPriority   = Expression.AddChecked(Expression.MultiplyChecked(priority, Expression.Constant(PriorityShift)), validatorPriority);
                    // todo вызывать один раз
                    var        targetValidationResults          = SelectTargetNode(result, treeRootType, resolvedArrayIndexes);
                    var        listAddMethod                    = HackHelpers.GetMethodDefinition <ValidationResultTreeNode>(x => x.AddValidationResult(null));
                    var        currentFormattedValidationResult = Expression.New(formattedValidationResultConstructor, currentValidationResult, value, formattedChains, currentPriority);
                    Expression addValidationResult              = Expression.Call(targetValidationResults, listAddMethod, currentFormattedValidationResult);
                    Expression validationResultIsNotNull        = Expression.NotEqual(currentValidationResult, Expression.Constant(null, typeof(ValidationResult)));
                    Expression validationResultIsNotOk          = Expression.NotEqual(Expression.Property(currentValidationResult, typeof(ValidationResult).GetProperty("Type", BindingFlags.Instance | BindingFlags.Public)), Expression.Constant(ValidationResultType.Ok));
                    Expression condition   = Expression.IfThen(Expression.AndAlso(validationResultIsNotNull, validationResultIsNotOk), addValidationResult);
                    var        localResult = Expression.IfThen(Expression.Not(Expression.Call(MutatorsHelperFunctions.DynamicMethod.MakeGenericMethod(typeof(bool)), Expression.Property(result, validationResultTreeNodeExhaustedProperty))), Expression.Block(new[] { currentValidationResult }, Expression.Assign(currentValidationResult, appliedValidator), condition));
                    localResults.Add(localResult);
                }

                var appliedValidators = Expression.Block(new[] { value }.Concat(currentIndexes), localResults);

                if (isDisabled == null)
                {
                    validationResults.Add(appliedValidators);
                }
                else
                {
                    Expression test = Expression.NotEqual(Expression.Convert(isDisabled, typeof(bool?)), Expression.Constant(true, typeof(bool?)));
                    validationResults.Add(Expression.IfThen(test, appliedValidators));
                }
            }
            public void BuildValidator(IPathFormatter pathFormatter, ModelConfigurationNode root, List <KeyValuePair <Expression, Expression> > aliases, Dictionary <ParameterExpression, ExpressionPathsBuilder.SinglePaths> paths, ParameterExpression result, Type treeRootType, ParameterExpression priority, List <Expression> validationResults)
            {
                foreach (var pair in mutators)
                {
                    BuildNodeValidator(pathFormatter, pair.Key, pair.Value, root, aliases, paths, result, treeRootType, priority, validationResults);
                }
                foreach (var pair in children)
                {
                    var edge  = pair.Key.Expression;
                    var child = pair.Value;

                    var array = ((MethodCallExpression)edge).Arguments[0];
                    LambdaExpression predicate = null;
                    var resolvedArray          = array.ResolveAliases(aliases);
                    var itemType = resolvedArray.Type.GetItemType();
                    var item     = Expression.Call(null, MutatorsHelperFunctions.EachMethod.MakeGenericMethod(itemType), array);
                    var index    = Expression.Call(null, MutatorsHelperFunctions.CurrentIndexMethod.MakeGenericMethod(itemType), item);
                    if (!resolvedArray.Type.IsArray)
                    {
                        // Filtered array
                        if (resolvedArray.NodeType == ExpressionType.Call)
                        {
                            var methodCallExpression = (MethodCallExpression)resolvedArray;
                            if (methodCallExpression.Method.IsWhereMethod())
                            {
                                resolvedArray = methodCallExpression.Arguments[0];
                                predicate     = (LambdaExpression)methodCallExpression.Arguments[1];
                            }
                        }
                    }

                    ParameterExpression[] indexes = null;
                    var parameter             = Expression.Parameter(itemType);
                    var adjustedResolvedArray = Expression.Call(selectMethod.MakeGenericMethod(itemType, itemType), resolvedArray, Expression.Lambda(parameter, parameter));
                    adjustedResolvedArray = Expression.Call(MutatorsHelperFunctions.EachMethod.MakeGenericMethod(itemType), adjustedResolvedArray);

                    var monster = new LinqEliminator().EliminateAndEnumerate(adjustedResolvedArray, (current, currentIndex, currentIndexes) =>
                    {
                        indexes = currentIndexes;
                        aliases.Add(new KeyValuePair <Expression, Expression>(current, item));
                        aliases.Add(new KeyValuePair <Expression, Expression>(currentIndex, index));
                        var currentPaths = ExpressionPathsBuilder.BuildPaths(adjustedResolvedArray, currentIndexes, paths);
                        //currentPaths.Add(currentIndex);
                        paths.Add(current, currentPaths);

                        var childValidationResults = new List <Expression>();
                        child.BuildValidator(pathFormatter, root, aliases, paths, result, treeRootType, priority, childValidationResults);
                        aliases.RemoveAt(aliases.Count - 1);
                        aliases.RemoveAt(aliases.Count - 1);

                        paths.Remove(current);

                        if (predicate != null)
                        {
                            var condition = Expression.Lambda(current, current).Merge(predicate).Body;
                            for (var i = 0; i < childValidationResults.Count; ++i)
                            {
                                childValidationResults[i] = Expression.IfThen(
                                    Expression.Equal(
                                        Expression.Convert(condition, typeof(bool?)),
                                        Expression.Constant(true, typeof(bool?))),
                                    childValidationResults[i]);
                            }
                        }

                        for (var i = 0; i < childValidationResults.Count; ++i)
                        {
                            childValidationResults[i] = childValidationResults[i].ExtractLoopInvariantFatExpressions(aliases.Where(p => p.Key is ParameterExpression).Select(p => (ParameterExpression)p.Key), e => e);
                        }

                        return(Expression.Block(childValidationResults.SplitToBatches()));
                    });

                    if (indexes != null && indexes.Length > 0)
                    {
                        monster = Expression.Block(indexes, monster);
                    }
                    validationResults.Add(monster);
                }
            }