Example #1
0
            internal override Expression VisitMemberAccess(MemberExpression m)
            {
                Debug.Assert(m != null, "m != null");

                this.leafExpressionIsMemberAccess = true;

                // Only allowed to project entities
                if (!ClientTypeUtil.TypeOrElementTypeIsEntity(m.Expression.Type) ||
                    IsCollectionProducingExpression(m.Expression))
                {
                    throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString()));
                }

                PropertyInfo pi;
                Expression   boundTarget;

                if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi, out boundTarget))
                {
                    Expression e = base.VisitMemberAccess(m);
                    Type       convertedType;
                    ResourceBinder.StripTo <Expression>(m.Expression, out convertedType);
                    box.AppendPropertyToPath(pi, convertedType, this.context);

                    this.leafExpressionIsMemberAccess = false;
                    return(e);
                }

                throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString()));
            }
Example #2
0
            /// <summary>
            /// Visits a member access expression in non-entity projections, validating that
            /// it's correct and recording the path visit to include in a projection if necessary.
            /// </summary>
            /// <param name="m">Expression to visit.</param>
            /// <returns>The same expression.</returns>
            /// <remarks>
            /// The projection analyzer runs after funcletization, so a member expression
            /// rather than a constant expression implies that this is correlated to
            /// a parameter, by dotting through the argument in valid cases, and possibly
            /// more complex cases in others like new DSC(p.Orders)*.Foo* &lt;- .Foo is invalid.
            /// </remarks>
            internal override Expression VisitMemberAccess(MemberExpression m)
            {
                Debug.Assert(m != null, "m != null");
                Type expressionType = m.Expression.Type;

                this.leafExpressionIsMemberAccess = true;

                // if primitive or nullable primitive, allow member access... i.e. calling Value on nullable<int>
                if (PrimitiveType.IsKnownNullableType(expressionType))
                {
                    this.leafExpressionIsMemberAccess = false;
                    return(base.VisitMemberAccess(m));
                }

                // Only allowed to project entities, also it is ok to do client side projections on complex types.
                // Details on the fix for the Dev11 bug 350541 "Inconsistency between Count() method call and Count property projection on clr type collections":
                //     Relax check to only throw if IsCollectionProducingExpression returns true.
                //     This enables client side projections (for example "Count") on Clr type collections, like ReadOnlyCollection (which is used in spatial types), ICollection, IList, etc.
                //     We already allow client side method calls (like Linq extension method "Count()") on clr type collections, so it makes client side projections consistent.
                //     Note: it will still throw for List<T> (because IsCollectionProducingExpression returns true for List<T>),
                //           however this is consistent with how we handle MethodCallExpression on clr type collections
                //           and changing IsCollectionProducingExpression seems risky at this point as it's used in a lot of places.
                if (IsCollectionProducingExpression(m.Expression))
                {
                    throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString()));
                }

                PropertyInfo pi;
                Expression   boundTarget;

                if (ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out pi, out boundTarget))
                {
                    Expression e = base.VisitMemberAccess(m);
                    if (ClientTypeUtil.TypeOrElementTypeIsEntity(expressionType))
                    {
                        Type convertedType;
                        ResourceBinder.StripTo <Expression>(m.Expression, out convertedType);
                        box.AppendPropertyToPath(pi, convertedType, this.context);
                        this.leafExpressionIsMemberAccess = false;
                    }

                    return(e);
                }

                throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString()));
            }