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);
                    this.builder.AppendPropertyToPath(pi, convertedType, this.context);

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

                throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString()));
            }
        internal override Expression VisitConditional(ConditionalExpression conditional)
        {
            Expression expressionBeforeNormalization = this.GetExpressionBeforeNormalization(conditional);

            if (expressionBeforeNormalization != conditional)
            {
                return(this.Visit(expressionBeforeNormalization));
            }
            ResourceBinder.PatternRules.MatchNullCheckResult nullCheck = ResourceBinder.PatternRules.MatchNullCheck(this.pathBuilder.LambdaParameterInScope, conditional);
            if (!nullCheck.Match || !ClientTypeUtil.TypeOrElementTypeIsEntity(ResourceBinder.StripConvertToAssignable(nullCheck.TestToNullExpression).Type))
            {
                Expression test = null;
                if (nullCheck.Match)
                {
                    Expression left = this.Visit(nullCheck.TestToNullExpression);
                    if (left.NodeType == ExpressionType.Convert)
                    {
                        left = ((UnaryExpression)left).Operand;
                    }
                    test = Expression.MakeBinary(ExpressionType.Equal, left, Expression.Constant(null));
                }
                if (test == null)
                {
                    test = this.Visit(conditional.Test);
                }
                Expression ifTrue  = this.Visit(conditional.IfTrue);
                Expression ifFalse = this.Visit(conditional.IfFalse);
                if (((test != conditional.Test) || (ifTrue != conditional.IfTrue)) || (ifFalse != conditional.IfFalse))
                {
                    return(Expression.Condition(test, ifTrue, ifFalse, ifTrue.Type.IsAssignableFrom(ifFalse.Type) ? ifTrue.Type : ifFalse.Type));
                }
            }
            return(this.RebindConditionalNullCheck(conditional, nullCheck));
        }
        /// <summary>Builds the Uri for the expression passed in.</summary>
        /// <param name="e">The expression to translate into a Uri</param>
        /// <returns>Query components</returns>
        internal QueryComponents Translate(Expression e)
        {
            Uri     uri;
            Version version;
            bool    addTrailingParens = false;
            Dictionary <Expression, Expression> normalizerRewrites = null;

            // short cut analysis if just a resource set or singleton resource.
            // note - to be backwards compatible with V1, will only append trailing () for queries
            // that include more then just a resource set.
            if (!(e is QueryableResourceExpression))
            {
                normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance);
                e = Evaluator.PartialEval(e);
                e = ExpressionNormalizer.Normalize(e, normalizerRewrites);
                e = ResourceBinder.Bind(e, this.Context);
                addTrailingParens = true;
            }

            UriWriter.Translate(this.Context, addTrailingParens, e, out uri, out version);
            ResourceExpression re            = e as ResourceExpression;
            Type             lastSegmentType = re.Projection == null ? re.ResourceType : re.Projection.Selector.Parameters[0].Type;
            LambdaExpression selector        = re.Projection == null ? null : re.Projection.Selector;

            return(new QueryComponents(uri, version, lastSegmentType, selector, normalizerRewrites));
        }
示例#4
0
            internal override Expression VisitMemberAccess(MemberExpression m)
            {
                PropertyInfo info;
                Expression   expression;
                Type         type = m.Expression.Type;

                this.leafExpressionIsMemberAccess = true;
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    this.leafExpressionIsMemberAccess = false;
                    return(base.VisitMemberAccess(m));
                }
                if (ProjectionAnalyzer.IsCollectionProducingExpression(m.Expression))
                {
                    throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString()));
                }
                if (!ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out info, out expression))
                {
                    throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString()));
                }
                Expression expression2 = base.VisitMemberAccess(m);

                if (ClientTypeUtil.TypeOrElementTypeIsEntity(type))
                {
                    Type type2;
                    ResourceBinder.StripTo <Expression>(m.Expression, out type2);
                    this.box.AppendPropertyToPath(info, type2, this.context);
                    this.leafExpressionIsMemberAccess = false;
                }
                return(expression2);
            }
示例#5
0
        /// <summary>
        /// QueryableResourceExpression visit method.
        /// </summary>
        /// <param name="rse">QueryableResourceExpression expression to visit</param>
        /// <returns>Visited QueryableResourceExpression expression</returns>
        internal override Expression VisitQueryableResourceExpression(QueryableResourceExpression rse)
        {
            if ((ResourceExpressionType)rse.NodeType == ResourceExpressionType.ResourceNavigationProperty)
            {
                if (rse.IsOperationInvocation && !(rse.Source is QueryableResourceExpression))
                {
                    var normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance);
                    var e = Evaluator.PartialEval(rse.Source);
                    e = ExpressionNormalizer.Normalize(e, normalizerRewrites);
                    e = ResourceBinder.Bind(e, this.context);
                    this.Visit(e);
                }
                else
                {
                    this.Visit(rse.Source);
                }

                this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(this.ExpressionToString(rse.MemberExpression, /*inPath*/ true));
            }
            else if (rse.MemberExpression != null)
            {
                // this is a resource set expression
                // we should be at the very beginning of
                // the URI
                Debug.Assert(this.uriBuilder.Length == 0, "The builder is not empty while we are adding a resourceset");
                string entitySetName = (String)((ConstantExpression)rse.MemberExpression).Value;
                this.uriBuilder.Append(this.context.BaseUriResolver.GetEntitySetUri(entitySetName));
            }
            else
            {
                this.uriBuilder.Append(this.context.BaseUriResolver.BaseUriOrNull);
            }

            WebUtil.RaiseVersion(ref this.uriVersion, rse.UriVersion);

            if (rse.ResourceTypeAs != null)
            {
                this.uriBuilder.Append(UriHelper.FORWARDSLASH);
                UriHelper.AppendTypeSegment(this.uriBuilder, rse.ResourceTypeAs, this.context, /*inPath*/ true, ref this.uriVersion);
            }

            if (rse.KeyPredicateConjuncts.Count > 0)
            {
                this.context.UrlKeyDelimiter.AppendKeyExpression(rse.GetKeyProperties(), kvp => ClientTypeUtil.GetServerDefinedName(kvp.Key), kvp => kvp.Value.Value, this.uriBuilder);
            }

            if (rse.IsOperationInvocation)
            {
                this.VisitOperationInvocation(rse);
            }

            if (rse.CountOption == CountOption.CountSegment)
            {
                // append $count segment: /$count
                this.uriBuilder.Append(UriHelper.FORWARDSLASH).Append(UriHelper.DOLLARSIGN).Append(UriHelper.COUNT);
            }

            this.VisitQueryOptions(rse);
            return(rse);
        }
示例#6
0
        internal ProjectionPathSegment(ProjectionPath startPath, MemberExpression memberExpression)
        {
            this.StartPath = startPath;
            Expression expression = ResourceBinder.StripTo <Expression>(memberExpression.Expression);

            this.Member         = memberExpression.Member.Name;
            this.ProjectionType = memberExpression.Type;
            this.SourceTypeAs   = (expression.NodeType == ExpressionType.TypeAs) ? expression.Type : null;
        }
        /// <summary>Gets a rewrite for the specified expression; null if none is found.</summary>
        /// <param name="expression">Expression to match.</param>
        /// <returns>A rewrite for the expression; possibly null.</returns>
        internal Expression GetRewrite(Expression expression)
        {
            Debug.Assert(expression != null, "expression != null");

            List <string> names = new List <string>();

            // This could be a MemberAccess wrapped in a type conversion, so strip off unnecessary conversions for each loop iteration.
            // E.g. (p.BestFriend As Person) instead of just p.BestFriend
            expression = ResourceBinder.StripTo <Expression>(expression);
            while (expression.NodeType == ExpressionType.MemberAccess || expression.NodeType == ExpressionType.TypeAs)
            {
                if (expression.NodeType == ExpressionType.MemberAccess)
                {
                    MemberExpression member = (MemberExpression)expression;
                    names.Add(member.Member.Name);
                    expression = ResourceBinder.StripTo <Expression>(member.Expression);
                }
                else
                {
                    expression = ResourceBinder.StripTo <Expression>(((UnaryExpression)expression).Operand);
                }
            }

            Expression result = null;

            foreach (var rewrite in this.rewrites)
            {
                if (rewrite.Root != expression)
                {
                    continue;
                }

                if (names.Count != rewrite.MemberNames.Length)
                {
                    continue;
                }

                bool match = true;
                for (int i = 0; i < names.Count && i < rewrite.MemberNames.Length; i++)
                {
                    if (names[names.Count - i - 1] != rewrite.MemberNames[i])
                    {
                        match = false;
                        break;
                    }
                }

                if (match)
                {
                    result = rewrite.RewriteExpression;
                    break;
                }
            }

            return(result);
        }
示例#8
0
 internal static void CheckChainedSequence(MethodCallExpression call, Type type)
 {
     if (ReflectionUtil.IsSequenceSelectMethod(call.Method))
     {
         MethodCallExpression expression = ResourceBinder.StripTo <MethodCallExpression>(call.Arguments[0]);
         if ((expression != null) && ReflectionUtil.IsSequenceSelectMethod(expression.Method))
         {
             throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(type, call.ToString()));
         }
     }
 }
示例#9
0
 internal static void CheckChainedSequence(MethodCallExpression call, Type type)
 {
     if (ReflectionUtil.IsSequenceMethod(call.Method, SequenceMethod.Select))
     {
         MethodCallExpression methodCallExpression = ResourceBinder.StripTo <MethodCallExpression>(call.Arguments[0]);
         if (methodCallExpression != null && ReflectionUtil.IsSequenceMethod(methodCallExpression.Method, SequenceMethod.Select))
         {
             throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Constructing or initializing instances of the type {0} with the expression {1} is not supported.", type, call.ToString()));
         }
     }
 }
示例#10
0
 internal static void CheckChainedSequence(MethodCallExpression call, Type type)
 {
     if (ReflectionUtil.IsSequenceMethod(call.Method, SequenceMethod.Select))
     {
         MethodCallExpression insideCall = ResourceBinder.StripTo <MethodCallExpression>(call.Arguments[0]);
         if (insideCall != null && ReflectionUtil.IsSequenceMethod(insideCall.Method, SequenceMethod.Select))
         {
             throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(type, call.ToString()));
         }
     }
 }
        internal override Expression VisitMemberAccess(MemberExpression m)
        {
            Type       type;
            Expression expression = base.VisitMemberAccess(m);
            Expression item       = ResourceBinder.StripTo <Expression>(m.Expression, out type);

            if (this.pathFromEntity.Contains(item))
            {
                this.pathFromEntity.Add(m);
            }
            return(expression);
        }
示例#12
0
        /// <summary>Initializes a new <see cref="ProjectionPathSegment"/> instance.</summary>
        /// <param name="startPath">Path on which this segment is located.</param>
        /// <param name="memberExpression">Member expression for the projection path; possibly null.</param>
        internal ProjectionPathSegment(ProjectionPath startPath, MemberExpression memberExpression)
        {
            Debug.Assert(startPath != null, "startPath != null");
            Debug.Assert(memberExpression != null, "memberExpression != null");

            this.StartPath = startPath;

            Expression source = ResourceBinder.StripTo <Expression>(memberExpression.Expression);

            this.Member         = ClientTypeUtil.GetServerDefinedName(memberExpression.Member);
            this.ProjectionType = memberExpression.Type;
            this.SourceTypeAs   = source.NodeType == ExpressionType.TypeAs ? source.Type : null;
        }
            /// <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);
                        this.builder.AppendPropertyToPath(pi, convertedType, this.context);
                        this.leafExpressionIsMemberAccess = false;
                    }

                    return(e);
                }

                throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString()));
            }
        /// <summary>Visits a member access expression.</summary>
        /// <param name="m">Access to visit.</param>
        /// <returns>The same expression.</returns>
        internal override Expression VisitMemberAccess(MemberExpression m)
        {
            Expression result = base.VisitMemberAccess(m);

            // Remove any unnecessary type conversions before checking to see if this expression is in the path.
            // For this purpose we should consider an expression to be equal to that same expression with an unnecessary conversion.
            // E.g. (p as Person) is the same as just p
            Type       convertedType;
            Expression strippedExp = ResourceBinder.StripTo <Expression>(m.Expression, out convertedType);

            if (this.pathFromEntity.Contains(strippedExp))
            {
                this.pathFromEntity.Add(m);
            }

            return(result);
        }
示例#15
0
        /// <summary>
        /// Converts expression to Uri
        /// </summary>
        /// <param name="e">The expression</param>
        /// <returns>Converted uri</returns>
        public virtual Uri Convert(Expression e)
        {
            Uri uri;

            Dictionary <Expression, Expression> rewrites = null;

            if (!(e is ResourceSetExpression))
            {
                rewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance);
                e        = Evaluator.PartialEval(e);
                e        = ExpressionNormalizer.Normalize(e, rewrites);
                e        = ResourceBinder.Bind(e);
            }

            UriWriter.Translate(false, e, out uri);

            return(uri);
        }
        internal QueryComponents Translate(Expression e)
        {
            Uri     uri;
            Version version;
            bool    addTrailingParens = false;
            Dictionary <Expression, Expression> rewrites = null;

            if (!(e is ResourceSetExpression))
            {
                rewrites          = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance);
                e                 = Evaluator.PartialEval(e);
                e                 = ExpressionNormalizer.Normalize(e, rewrites);
                e                 = ResourceBinder.Bind(e, this.Context);
                addTrailingParens = true;
            }
            UriWriter.Translate(this.Context, addTrailingParens, e, out uri, out version);
            ResourceExpression expression = e as ResourceExpression;
            Type lastSegmentType          = (expression.Projection == null) ? expression.ResourceType : expression.Projection.Selector.Parameters[0].Type;

            return(new QueryComponents(uri, version, lastSegmentType, (expression.Projection == null) ? null : expression.Projection.Selector, rewrites));
        }
示例#17
0
        internal Expression GetRewrite(Expression expression)
        {
            List <string> list = new List <string>();

            expression = ResourceBinder.StripTo <Expression>(expression);
            while ((expression.NodeType == ExpressionType.MemberAccess) || (expression.NodeType == ExpressionType.TypeAs))
            {
                if (expression.NodeType == ExpressionType.MemberAccess)
                {
                    MemberExpression expression2 = (MemberExpression)expression;
                    list.Add(expression2.Member.Name);
                    expression = ResourceBinder.StripTo <Expression>(expression2.Expression);
                }
                else
                {
                    expression = ResourceBinder.StripTo <Expression>(((UnaryExpression)expression).Operand);
                }
            }
            foreach (MemberInitRewrite rewrite in this.rewrites)
            {
                if ((rewrite.Root != expression) || (list.Count != rewrite.MemberNames.Length))
                {
                    continue;
                }
                bool flag = true;
                for (int i = 0; (i < list.Count) && (i < rewrite.MemberNames.Length); i++)
                {
                    if (list[(list.Count - i) - 1] != rewrite.MemberNames[i])
                    {
                        flag = false;
                        break;
                    }
                }
                if (flag)
                {
                    return(rewrite.RewriteExpression);
                }
            }
            return(null);
        }
示例#18
0
        internal ExecutionInfo Bind()
        {
            ExecutionInfo retVal = new ExecutionInfo();

            // IQueryable impl
            if (this.Expression != null)
            {
                Dictionary <Expression, Expression> normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance);

                // Step 1. Evaluate any local evaluatable expressions ( lambdas etc)
                Expression partialEvaluatedExpression = Evaluator.PartialEval(this.Expression);

                // Step 2. Normalize expression, replace String Comparisons etc.
                Expression normalizedExpression = ExpressionNormalizer.Normalize(partialEvaluatedExpression, normalizerRewrites);

                // Step 3. Bind Expression, Analyze predicates and create query option expressions. End result is a single ResourceSetExpression
                Expression boundExpression = ResourceBinder.Bind(normalizedExpression);

                // Step 4. Parse the Bound expression into sub components, i.e. take count, filter, select columns, request options, opcontext, etc.
                ExpressionParser parser = new ExpressionParser();
                parser.Translate(boundExpression);

                // Step 5. Store query components & params
                this.TakeCount          = parser.TakeCount;
                this.FilterString       = parser.FilterString;
                this.SelectColumns      = parser.SelectColumns;
                retVal.RequestOptions   = parser.RequestOptions;
                retVal.OperationContext = parser.OperationContext;

                // Step 6. If projection & no resolver then generate a resolver to perform the projection
                if (parser.Resolver == null)
                {
                    if (parser.Projection != null && parser.Projection.Selector != ProjectionQueryOptionExpression.DefaultLambda)
                    {
                        Type intermediateType = parser.Projection.Selector.Parameters[0].Type;

                        // Convert Expression to take type object as input to allow for direct invocation.
                        ParameterExpression paramExpr = Expression.Parameter(typeof(object));

                        Func <object, TElement> projectorFunc = Expression.Lambda <Func <object, TElement> >(
                            Expression.Invoke(parser.Projection.Selector, Expression.Convert(paramExpr, intermediateType)), paramExpr).Compile();

                        // Generate a resolver to do the projection.
                        retVal.Resolver = (pk, rk, ts, props, etag) =>
                        {
                            // Parse to intermediate type
                            ITableEntity intermediateObject = (ITableEntity)EntityUtilities.InstantiateEntityFromType(intermediateType);
                            intermediateObject.PartitionKey = pk;
                            intermediateObject.RowKey       = rk;
                            intermediateObject.Timestamp    = ts;
                            intermediateObject.ReadEntity(props, parser.OperationContext);
                            intermediateObject.ETag = etag;

                            // Invoke lambda expression
                            return(projectorFunc(intermediateObject));
                        };
                    }
                    else
                    {
                        // No op - No resolver or projection specified.
                    }
                }
                else
                {
                    retVal.Resolver = (EntityResolver <TElement>)parser.Resolver.Value;
                }
            }

            retVal.RequestOptions   = TableRequestOptions.ApplyDefaults(retVal.RequestOptions, this.queryProvider.Table.ServiceClient);
            retVal.OperationContext = retVal.OperationContext ?? new OperationContext();
            return(retVal);
        }
示例#19
0
        /// <summary>
        /// Rebinds a conditional that performs a null check on an entity.
        /// </summary>
        /// <param name="conditional">Conditional expression.</param>
        /// <param name="nullCheck">Results of null check analysis.</param>
        /// <returns>The rebound expression.</returns>
        /// <remarks>
        /// Do a rewrite to avoid creating a type in the null check:
        ///   a.b == null ? null : [a.b]-based expression
        /// becomes
        ///   ProjectionIsNull(a.b) ? null : [a.b]-based expression
        /// </remarks>
        private Expression RebindConditionalNullCheck(ConditionalExpression conditional, ResourceBinder.PatternRules.MatchNullCheckResult nullCheck)
        {
            Debug.Assert(conditional != null, "conditional != null");
            Debug.Assert(nullCheck.Match, "nullCheck.Match -- otherwise no reason to call this rebind method");

            Expression testToNullForProjection = this.Visit(nullCheck.TestToNullExpression);
            Expression assignForProjection = this.Visit(nullCheck.AssignExpression);
            ExpressionAnnotation testToNullAnnotation;
            if (!this.annotations.TryGetValue(testToNullForProjection, out testToNullAnnotation))
            {
                return base.VisitConditional(conditional);
            }

            ProjectionPathSegment testToNullSegment = testToNullAnnotation.Segment;

            Expression testToNullThroughMethod = this.CallCheckValueForPathIsNull(
                testToNullSegment.StartPath.RootEntry,
                testToNullSegment.StartPath.ExpectedRootType,
                testToNullSegment.StartPath);

            Expression test = testToNullThroughMethod;
            Expression iftrue = Expression.Constant(null, assignForProjection.Type);
            Expression iffalse = assignForProjection;
            Expression result = Expression.Condition(test, iftrue, iffalse);
            return result;
        }
示例#20
0
 private Expression RebindConditionalNullCheck(ConditionalExpression conditional, ResourceBinder.PatternRules.MatchNullCheckResult nullCheck)
 {
     ExpressionAnnotation annotation;
     Expression key = this.Visit(nullCheck.TestToNullExpression);
     Expression expression2 = this.Visit(nullCheck.AssignExpression);
     if (!this.annotations.TryGetValue(key, out annotation))
     {
         return base.VisitConditional(conditional);
     }
     ProjectionPathSegment segment = annotation.Segment;
     Expression test = this.CallCheckValueForPathIsNull(segment.StartPath.RootEntry, segment.StartPath.ExpectedRootType, segment.StartPath);
     Expression ifTrue = Expression.Constant(null, expression2.Type);
     Expression ifFalse = expression2;
     return Expression.Condition(test, ifTrue, ifFalse);
 }