Пример #1
0
        internal override Expression VisitMemberInit(MemberInitExpression init)
        {
            Expression result = init;
            MemberAssignmentAnalysis previousNested = null;

            foreach (var binding in init.Bindings)
            {
                MemberAssignment assignment = binding as MemberAssignment;
                if (assignment == null)
                {
                    continue;
                }

                MemberAssignmentAnalysis nested = MemberAssignmentAnalysis.Analyze(this.entity, assignment.Expression);
                if (nested.MultiplePathsFound)
                {
                    this.multiplePathsFound = true;
                    break;
                }

                Exception incompatibleException = nested.CheckCompatibleAssignments(init.Type, ref previousNested);
                if (incompatibleException != null)
                {
                    this.incompatibleAssignmentsException = incompatibleException;
                    break;
                }

                if (this.pathFromEntity.Count == 0)
                {
                    this.pathFromEntity.AddRange(nested.GetExpressionsToTargetEntity());
                }
            }

            return(result);
        }
Пример #2
0
        /// <summary>
        /// If there is a MemberInitExpression 'new Person { ID = p.ID, Friend = new Person { ID = p.Friend.ID }}'
        /// or a NewExpression 'new { ID = p.ID, Friend = new { ID = p.Friend.ID }}',
        /// this method validates against the RHS of the member assigment, the expression "p.ID" for example.
        /// </summary>
        /// <param name="expressionToAssign">The expression to validate.</param>
        /// <param name="initType">Type of the MemberInit or the New expression.</param>
        /// <param name="previousNested">The outter nested initializer of the current initializer we are checking.</param>
        /// <returns>true if the expression to assign is fine; false otherwise.</returns>
        private bool CheckCompatibleAssigmentExpression(Expression expressionToAssign, Type initType, ref MemberAssignmentAnalysis previousNested)
        {
            MemberAssignmentAnalysis nested = MemberAssignmentAnalysis.Analyze(this.entity, expressionToAssign);

            if (nested.MultiplePathsFound)
            {
                this.multiplePathsFound = true;
                return(false);
            }

            // When we're visitng a nested entity initializer, we're exactly one level above that.
            Exception incompatibleException = nested.CheckCompatibleAssignments(initType, ref previousNested);

            if (incompatibleException != null)
            {
                this.incompatibleAssignmentsException = incompatibleException;
                return(false);
            }

            if (this.pathFromEntity.Count == 0)
            {
                this.pathFromEntity.AddRange(nested.GetExpressionsToTargetEntity());
            }

            return(true);
        }
 internal Exception CheckCompatibleAssignments(Type targetType, ref MemberAssignmentAnalysis previous)
 {
     if (previous == null)
     {
         previous = this;
         return(null);
     }
     Expression[] expressionsToTargetEntity = previous.GetExpressionsToTargetEntity();
     Expression[] candidate = this.GetExpressionsToTargetEntity();
     return(CheckCompatibleAssignments(targetType, expressionsToTargetEntity, candidate));
 }
Пример #4
0
 internal Exception CheckCompatibleAssignments(Type targetType, ref MemberAssignmentAnalysis previous)
 {
     if (previous == null)
     {
         previous = this;
         return null;
     }
     Expression[] expressionsToTargetEntity = previous.GetExpressionsToTargetEntity();
     Expression[] candidate = this.GetExpressionsToTargetEntity();
     return CheckCompatibleAssignments(targetType, expressionsToTargetEntity, candidate);
 }
        private bool CheckCompatibleAssigmentExpression(Expression expressionToAssign, Type initType, ref MemberAssignmentAnalysis previousNested)
        {
            MemberAssignmentAnalysis analysis = Analyze(this.entity, expressionToAssign);

            if (analysis.MultiplePathsFound)
            {
                this.multiplePathsFound = true;
                return(false);
            }
            Exception exception = analysis.CheckCompatibleAssignments(initType, ref previousNested);

            if (exception != null)
            {
                this.incompatibleAssignmentsException = exception;
                return(false);
            }
            if (this.pathFromEntity.Count == 0)
            {
                this.pathFromEntity.AddRange(analysis.GetExpressionsToTargetEntity());
            }
            return(true);
        }
Пример #6
0
        private Expression RebindEntityMemberInit(MemberInitExpression init)
        {
            Debug.Assert(init != null, "init != null");
            Debug.Assert(init.Bindings.Count > 0, "init.Bindings.Count > 0 -- otherwise this is just empty construction");

            Expression[] expressions;
            if (!this.pathBuilder.HasRewrites)
            {
                MemberAssignmentAnalysis propertyAnalysis = MemberAssignmentAnalysis.Analyze(
                    this.pathBuilder.LambdaParameterInScope,
                    ((MemberAssignment)init.Bindings[0]).Expression);
                expressions = propertyAnalysis.GetExpressionsToTargetEntity();
                Debug.Assert(expressions.Length != 0, "expressions.Length != 0 -- otherwise there is no correlation to parameter in entity member init");
            }
            else
            {
                expressions = MemberAssignmentAnalysis.EmptyExpressionArray;
            }

            Expression    entryParameterAtMemberInit = this.pathBuilder.ParameterEntryInScope;
            List <string> propertyNames = new List <string>();
            List <Func <object, object, Type, object> > propertyFunctions = new List <Func <object, object, Type, object> >();
            Type       projectedType           = init.NewExpression.Type;
            Expression projectedTypeExpression = Expression.Constant(projectedType, typeof(Type));

            Expression entryToInitValue;            Expression expectedParamValue;            ParameterExpression entryParameterForMembers;            ParameterExpression expectedParameterForMembers;            string[] expressionNames = expressions.Skip(1).Select(e => ((MemberExpression)e).Member.Name).ToArray();

            if (expressions.Length <= 1)
            {
                entryToInitValue            = this.pathBuilder.ParameterEntryInScope;
                expectedParamValue          = this.pathBuilder.ExpectedParamTypeInScope;
                entryParameterForMembers    = (ParameterExpression)this.pathBuilder.ParameterEntryInScope;
                expectedParameterForMembers = (ParameterExpression)this.pathBuilder.ExpectedParamTypeInScope;
            }
            else
            {
                entryToInitValue            = this.GetDeepestEntry(expressions);
                expectedParamValue          = projectedTypeExpression;
                entryParameterForMembers    = Expression.Parameter(typeof(object), "subentry" + this.identifierId++);
                expectedParameterForMembers = (ParameterExpression)this.pathBuilder.ExpectedParamTypeInScope;

                ProjectionPath entryPath = new ProjectionPath(
                    (ParameterExpression)this.pathBuilder.LambdaParameterInScope,
                    this.pathBuilder.ExpectedParamTypeInScope,
                    this.pathBuilder.ParameterEntryInScope,
                    expressions.Skip(1));

                this.annotations.Add(entryToInitValue, new ExpressionAnnotation()
                {
                    Segment = entryPath[entryPath.Count - 1]
                });
                this.annotations.Add(entryParameterForMembers, new ExpressionAnnotation()
                {
                    Segment = entryPath[entryPath.Count - 1]
                });
                this.pathBuilder.RegisterRewrite(this.pathBuilder.LambdaParameterInScope, expressionNames, entryParameterForMembers);
            }

            for (int i = 0; i < init.Bindings.Count; i++)
            {
                MemberAssignment assignment = (MemberAssignment)init.Bindings[i];
                propertyNames.Add(assignment.Member.Name);

                LambdaExpression propertyLambda;

                if ((ClientType.CheckElementTypeIsEntity(assignment.Member.ReflectedType) &&
                     assignment.Expression.NodeType == ExpressionType.MemberInit))
                {
                    Expression nestedEntry = CallMaterializer(
                        "ProjectionGetEntry",
                        entryParameterAtMemberInit,
                        Expression.Constant(assignment.Member.Name, typeof(string)));
                    ParameterExpression nestedEntryParameter = Expression.Parameter(
                        typeof(object),
                        "subentry" + this.identifierId++);

                    ProjectionPath       entryPath;
                    ExpressionAnnotation entryAnnotation;
                    if (this.annotations.TryGetValue(this.pathBuilder.ParameterEntryInScope, out entryAnnotation))
                    {
                        entryPath = new ProjectionPath(
                            (ParameterExpression)this.pathBuilder.LambdaParameterInScope,
                            this.pathBuilder.ExpectedParamTypeInScope,
                            entryParameterAtMemberInit);
                        entryPath.AddRange(entryAnnotation.Segment.StartPath);
                    }
                    else
                    {
                        entryPath = new ProjectionPath(
                            (ParameterExpression)this.pathBuilder.LambdaParameterInScope,
                            this.pathBuilder.ExpectedParamTypeInScope,
                            entryParameterAtMemberInit,
                            expressions.Skip(1));
                    }

                    ProjectionPathSegment nestedSegment = new ProjectionPathSegment(
                        entryPath,
                        assignment.Member.Name,
                        assignment.Member.ReflectedType);

                    entryPath.Add(nestedSegment);

                    string[] names = (entryPath.Where(m => m.Member != null).Select(m => m.Member)).ToArray();

                    this.annotations.Add(nestedEntryParameter, new ExpressionAnnotation()
                    {
                        Segment = nestedSegment
                    });
                    this.pathBuilder.RegisterRewrite(this.pathBuilder.LambdaParameterInScope, names, nestedEntryParameter);
                    Expression e = this.Visit(assignment.Expression);
                    this.pathBuilder.RevokeRewrite(this.pathBuilder.LambdaParameterInScope, names);
                    this.annotations.Remove(nestedEntryParameter);

                    e = Expression.Convert(e, typeof(object));
                    ParameterExpression[] parameters =
                        new ParameterExpression[]
                    {
                        this.materializerExpression,
                        nestedEntryParameter,
                        expectedParameterForMembers,
                    };
                    propertyLambda = Expression.Lambda(e, parameters);

                    Expression[] nestedParams =
                        new Expression[]
                    {
                        this.materializerExpression,
                        nestedEntry,
                        expectedParameterForMembers,
                    };
                    var invokeParameters =
                        new ParameterExpression[]
                    {
                        this.materializerExpression,
                        (ParameterExpression)entryParameterAtMemberInit,
                        expectedParameterForMembers,
                    };
                    propertyLambda = Expression.Lambda(Expression.Invoke(propertyLambda, nestedParams), invokeParameters);
                }
                else
                {
                    Expression e = this.Visit(assignment.Expression);
                    e = Expression.Convert(e, typeof(object));
                    ParameterExpression[] parameters =
                        new ParameterExpression[]
                    {
                        this.materializerExpression,
                        entryParameterForMembers,
                        expectedParameterForMembers,
                    };
                    propertyLambda = Expression.Lambda(e, parameters);
                }

#if TRACE_CLIENT_PROJECTIONS
                Trace.WriteLine("Compiling lambda for " + assignment.Member.Name + ": " + propertyLambda);
#endif
                propertyFunctions.Add((Func <object, object, Type, object>)propertyLambda.Compile());
            }

            for (int i = 1; i < expressions.Length; i++)
            {
                this.pathBuilder.RevokeRewrite(this.pathBuilder.LambdaParameterInScope, expressionNames);
                this.annotations.Remove(entryToInitValue);
                this.annotations.Remove(entryParameterForMembers);
            }

            Expression reboundExpression = CallMaterializer(
                "ProjectionInitializeEntity",
                this.materializerExpression,
                entryToInitValue,
                expectedParamValue,
                projectedTypeExpression,
                Expression.Constant(propertyNames.ToArray()),
                Expression.Constant(propertyFunctions.ToArray()));

            return(Expression.Convert(reboundExpression, projectedType));
        }