public InlineFlattenedTypeVisitor(NewExpression anonymousConstructor, ParameterExpression converted, ParameterExpression initial, AnonymousTypeFlattener flattener) : base(anonymousConstructor) { _initial = initial; _converted = converted; _flattener = flattener; }
protected internal override QueryOperator VisitSelect(SelectOperator op) { var src = VisitAndConvert <MonadMember>(op.Source); var selector = Visit(op.Selector); if (TryCast <SelectOperator>(src, OperatorType.Select, out SelectOperator select1) && TryExtractNullaryLambdaBody <LambdaExpression>(select1.Selector, ExpressionType.Lambda, out LambdaExpression selector1) && TryGetNewAnonymousType(selector1.Body, out NewExpression anonCtor1) && TryExtractNullaryLambdaBody <LambdaExpression>(selector, ExpressionType.Lambda, out LambdaExpression selector2)) { if (TryGetNewAnonymousType(selector2.Body, out NewExpression anonCtor2)) { if (anonCtor2.Members.Count > 0 && anonCtor2.Arguments[0] == selector2.Parameters[0]) { var newArgs = new Expression[anonCtor2.Members.Count]; newArgs[0] = anonCtor1; for (var i = 1; i < newArgs.Length; i++) { var visitor = new ValidateMemberAccessesAndInlineVisitor(anonCtor1, selector1.Parameters[0], selector2.Parameters[0]); newArgs[i] = visitor.Visit(anonCtor2.Arguments[i]); if (!visitor.Valid) { return(UpdateSelect(op, src, selector)); } } var updated = anonCtor2.Update(newArgs); var newBody = DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda(Expression.Lambda(updated, selector1.Parameters[0])), Array.Empty <QueryTree>() ); return (op.QueryExpressionFactory.Select( op.ElementType, select1.InputElementType, select1.Source, newBody )); } } else { var flatteningValidationVisitor = new ValidateMemberAccessVisitor(anonCtor1, selector2.Parameters[0]); flatteningValidationVisitor.Visit(selector2.Body); if (flatteningValidationVisitor.Valid) { var flattener = new AnonymousTypeFlattener(anonCtor1); if (flattener.TryConstruct(out NewExpression c)) { var t = c.Type; var newParam = Expression.Parameter(t); var flatteningVisitor = new InlineFlattenedTypeVisitor(anonCtor1, newParam, selector2.Parameters[0], flattener); var f = flatteningVisitor.Visit(selector2.Body); var child = select1.QueryExpressionFactory.Select( t, select1.InputElementType, select1.Source, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda(Expression.Lambda(c, selector1.Parameters[0])), Array.Empty <QueryTree>() ) ); return (op.QueryExpressionFactory.Select( op.ElementType, t, child, DefaultQueryExpressionFactory.Instance.LambdaAbstraction( Expression.Lambda(Expression.Lambda(f, newParam)), Array.Empty <QueryTree>() ) )); } } } } return(UpdateSelect(op, src, selector)); }