ExpressionWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / ALinq / ExpressionWriter.cs / 1305376 / ExpressionWriter.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Serializes sub-expressions as query options in the URI.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client
{
    #region Namespaces. 

    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Linq.Expressions; 
    using System.Reflection;
    using System.Text;

    #endregion Namespaces. 

    ///  
    /// Special visitor to serialize supported expression as query parameters 
    /// in the generated URI.
    ///  
    internal class ExpressionWriter : DataServiceALinqExpressionVisitor
    {
        #region Private fields.
 
        /// Internal buffer.
        private readonly StringBuilder builder; 
 
        /// Data context used to generate type names for types.
        private readonly DataServiceContext context; 

        /// Stack of expressions being visited.
        private readonly Stack expressionStack;
 
        /// set if can't translate expression
        private bool cantTranslateExpression; 
 
        /// Parent expression of the current expression (expression.Peek()); possibly null.
        private Expression parent; 

        #endregion Private fields.

        ///  
        /// Creates an ExpressionWriter for the specified .
        ///  
        /// Data context used to generate type names for types. 
        private ExpressionWriter(DataServiceContext context)
        { 
            Debug.Assert(context != null, "context != null");
            this.context = context;
            this.builder = new StringBuilder();
            this.expressionStack = new Stack(); 
            this.expressionStack.Push(null);
        } 
 
        /// 
        /// Serializes an expression to a string 
        /// 
        /// Data context used to generate type names for types.
        /// Expression to serialize
        /// serialized expression 
        internal static string ExpressionToString(DataServiceContext context, Expression e)
        { 
            ExpressionWriter ew = new ExpressionWriter(context); 
            string serialized = ew.Translate(e);
            if (ew.cantTranslateExpression) 
            {
                throw new NotSupportedException(Strings.ALinq_CantTranslateExpression(e.ToString()));
            }
 
            return serialized;
        } 
 
        /// Main visit method.
        /// Expression to visit 
        /// Visited expression
        internal override Expression Visit(Expression exp)
        {
            this.parent = this.expressionStack.Peek(); 
            this.expressionStack.Push(exp);
            Expression result = base.Visit(exp); 
            this.expressionStack.Pop(); 
            return result;
        } 

        /// 
        /// ConditionalExpression visit method
        ///  
        /// The ConditionalExpression expression to visit
        /// The visited ConditionalExpression expression  
        internal override Expression VisitConditional(ConditionalExpression c) 
        {
            this.cantTranslateExpression = true; 
            return c;
        }

        ///  
        /// LambdaExpression visit method
        ///  
        /// The LambdaExpression to visit 
        /// The visited LambdaExpression
        internal override Expression VisitLambda(LambdaExpression lambda) 
        {
            this.cantTranslateExpression = true;
            return lambda;
        } 

        ///  
        /// NewExpression visit method 
        /// 
        /// The NewExpression to visit 
        /// The visited NewExpression
        internal override NewExpression VisitNew(NewExpression nex)
        {
            this.cantTranslateExpression = true; 
            return nex;
        } 
 
        /// 
        /// MemberInitExpression visit method 
        /// 
        /// The MemberInitExpression to visit
        /// The visited MemberInitExpression
        internal override Expression VisitMemberInit(MemberInitExpression init) 
        {
            this.cantTranslateExpression = true; 
            return init; 
        }
 
        /// 
        /// ListInitExpression visit method
        /// 
        /// The ListInitExpression to visit 
        /// The visited ListInitExpression
        internal override Expression VisitListInit(ListInitExpression init) 
        { 
            this.cantTranslateExpression = true;
            return init; 
        }

        /// 
        /// NewArrayExpression visit method 
        /// 
        /// The NewArrayExpression to visit 
        /// The visited NewArrayExpression 
        internal override Expression VisitNewArray(NewArrayExpression na)
        { 
            this.cantTranslateExpression = true;
            return na;
        }
 
        /// 
        /// InvocationExpression visit method 
        ///  
        /// The InvocationExpression to visit
        /// The visited InvocationExpression 
        internal override Expression VisitInvocation(InvocationExpression iv)
        {
            this.cantTranslateExpression = true;
            return iv; 
        }
 
        ///  
        /// Input resource set references are intentionally omitted from the URL string.
        ///  
        /// The input reference
        /// The same input reference expression
        internal override Expression VisitInputReferenceExpression(InputReferenceExpression ire)
        { 
            // This method intentionally does not write anything to the URI.
            // This is how 'Where(.Id == 5)' becomes '$filter=Id eq 5'. 
            Debug.Assert(ire != null, "ire != null"); 
            if (this.parent == null || this.parent.NodeType != ExpressionType.MemberAccess)
            { 
                // Ideally we refer to the parent expression as the un-translatable one,
                // because we cannot reference 'this' as a standalone expression; however
                // if the parent is null for any reasonn, we fall back to the expression itself.
                string expressionText = (this.parent != null) ? this.parent.ToString() : ire.ToString(); 
                throw new NotSupportedException(Strings.ALinq_CantTranslateExpression(expressionText));
            } 
 
            return ire;
        } 

        /// 
        /// MethodCallExpression visit method
        ///  
        /// The MethodCallExpression expression to visit
        /// The visited MethodCallExpression expression  
        internal override Expression VisitMethodCall(MethodCallExpression m) 
        {
            string methodName; 
            if (TypeSystem.TryGetQueryOptionMethod(m.Method, out methodName))
            {
                this.builder.Append(methodName);
                this.builder.Append(UriHelper.LEFTPAREN); 

                // There is a single function, 'substringof', which reorders its argument with 
                // respect to the CLR method. Thus handling it as a special case rather than 
                // using a more general argument reordering mechanism.
                if (methodName == "substringof") 
                {
                    Debug.Assert(m.Method.Name == "Contains", "m.Method.Name == 'Contains'");
                    Debug.Assert(m.Object != null, "m.Object != null");
                    Debug.Assert(m.Arguments.Count == 1, "m.Arguments.Count == 1"); 
                    this.Visit(m.Arguments[0]);
                    this.builder.Append(UriHelper.COMMA); 
                    this.Visit(m.Object); 
                }
                else 
                {
                    if (m.Object != null)
                    {
                        this.Visit(m.Object); 
                    }
 
                    if (m.Arguments.Count > 0) 
                    {
                        if (m.Object != null) 
                        {
                            this.builder.Append(UriHelper.COMMA);
                        }
 
                        for (int ii = 0; ii < m.Arguments.Count; ii++)
                        { 
                            this.Visit(m.Arguments[ii]); 
                            if (ii < m.Arguments.Count - 1)
                            { 
                                this.builder.Append(UriHelper.COMMA);
                            }
                        }
                    } 
                }
 
                this.builder.Append(UriHelper.RIGHTPAREN); 
            }
            else 
            {
                this.cantTranslateExpression = true;
            }
 
            return m;
        } 
 
        /// 
        /// Serializes an MemberExpression to a string 
        /// 
        /// Expression to serialize
        /// MemberExpression
        internal override Expression VisitMemberAccess(MemberExpression m) 
        {
            if (m.Member is FieldInfo) 
            { 
                throw new NotSupportedException(Strings.ALinq_CantReferToPublicField(m.Member.Name));
            } 

            Expression e = this.Visit(m.Expression);

            // if this is a Nullable instance, don't write out /Value since not supported by server 
            if (m.Member.Name == "Value" && m.Member.DeclaringType.IsGenericType
                && m.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>)) 
            { 
                return m;
            } 

            if (!IsInputReference(e))
            {
                this.builder.Append(UriHelper.FORWARDSLASH); 
            }
 
            this.builder.Append(m.Member.Name); 

            return m; 
        }

        /// 
        /// ConstantExpression visit method 
        /// 
        /// The ConstantExpression expression to visit 
        /// The visited ConstantExpression expression  
        internal override Expression VisitConstant(ConstantExpression c)
        { 
            string result = null;
            if (c.Value == null)
            {
                this.builder.Append(UriHelper.NULL); 
                return c;
            } 
            else if (!ClientConvert.TryKeyPrimitiveToString(c.Value, out result)) 
            {
                throw new InvalidOperationException(Strings.ALinq_CouldNotConvert(c.Value)); 
            }

            Debug.Assert(result != null, "result != null");
            this.builder.Append(System.Uri.EscapeDataString(result)); 
            return c;
        } 
 
        /// 
        /// Serializes an UnaryExpression to a string 
        /// 
        /// Expression to serialize
        /// UnaryExpression
        internal override Expression VisitUnary(UnaryExpression u) 
        {
            switch (u.NodeType) 
            { 
                case ExpressionType.Not:
                    this.builder.Append(UriHelper.NOT); 
                    this.builder.Append(UriHelper.SPACE);
                    this.VisitOperand(u.Operand);
                    break;
                case ExpressionType.Negate: 
                case ExpressionType.NegateChecked:
                    this.builder.Append(UriHelper.SPACE); 
                    this.builder.Append(UriHelper.NEGATE); 
                    this.VisitOperand(u.Operand);
                    break; 
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    if (u.Type != typeof(object))
                    { 
                        this.builder.Append(UriHelper.CAST);
                        this.builder.Append(UriHelper.LEFTPAREN); 
                        if (!IsInputReference(u.Operand)) 
                        {
                            this.Visit(u.Operand); 
                            this.builder.Append(UriHelper.COMMA);
                        }

                        this.builder.Append(UriHelper.QUOTE); 
                        this.builder.Append(this.TypeNameForUri(u.Type));
                        this.builder.Append(UriHelper.QUOTE); 
                        this.builder.Append(UriHelper.RIGHTPAREN); 
                    }
                    else 
                    {
                        if (!IsInputReference(u.Operand))
                        {
                            this.Visit(u.Operand); 
                        }
                    } 
 
                    break;
                case ExpressionType.UnaryPlus: 
                    // no-op always ignore.
                    break;
                default:
                    this.cantTranslateExpression = true; 
                    break;
            } 
 
            return u;
        } 

        /// 
        /// Serializes an BinaryExpression to a string
        ///  
        /// BinaryExpression to serialize
        /// serialized expression 
        internal override Expression VisitBinary(BinaryExpression b) 
        {
            this.VisitOperand(b.Left); 
            this.builder.Append(UriHelper.SPACE);
            switch (b.NodeType)
            {
                case ExpressionType.AndAlso: 
                case ExpressionType.And:
                    this.builder.Append(UriHelper.AND); 
                    break; 
                case ExpressionType.OrElse:
                case ExpressionType.Or: 
                    this.builder.Append(UriHelper.OR);
                    break;
                case ExpressionType.Equal:
                    this.builder.Append(UriHelper.EQ); 
                    break;
                case ExpressionType.NotEqual: 
                    this.builder.Append(UriHelper.NE); 
                    break;
                case ExpressionType.LessThan: 
                    this.builder.Append(UriHelper.LT);
                    break;
                case ExpressionType.LessThanOrEqual:
                    this.builder.Append(UriHelper.LE); 
                    break;
                case ExpressionType.GreaterThan: 
                    this.builder.Append(UriHelper.GT); 
                    break;
                case ExpressionType.GreaterThanOrEqual: 
                    this.builder.Append(UriHelper.GE);
                    break;
                case ExpressionType.Add:
                case ExpressionType.AddChecked: 
                    this.builder.Append(UriHelper.ADD);
                    break; 
                case ExpressionType.Subtract: 
                case ExpressionType.SubtractChecked:
                    this.builder.Append(UriHelper.SUB); 
                    break;
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    this.builder.Append(UriHelper.MUL); 
                    break;
                case ExpressionType.Divide: 
                    this.builder.Append(UriHelper.DIV); 
                    break;
                case ExpressionType.Modulo: 
                    this.builder.Append(UriHelper.MOD);
                    break;
                case ExpressionType.ArrayIndex:
                case ExpressionType.Power: 
                case ExpressionType.Coalesce:
                case ExpressionType.ExclusiveOr: 
                case ExpressionType.LeftShift: 
                case ExpressionType.RightShift:
                default: 
                    this.cantTranslateExpression = true;
                    break;
            }
 
            this.builder.Append(UriHelper.SPACE);
            this.VisitOperand(b.Right); 
            return b; 
        }
 
        /// 
        /// Serializes an TypeBinaryExpression to a string
        /// 
        /// TypeBinaryExpression to serialize 
        /// serialized expression
        internal override Expression VisitTypeIs(TypeBinaryExpression b) 
        { 
            this.builder.Append(UriHelper.ISOF);
            this.builder.Append(UriHelper.LEFTPAREN); 

            if (!IsInputReference(b.Expression))
            {
                this.Visit(b.Expression); 
                this.builder.Append(UriHelper.COMMA);
                this.builder.Append(UriHelper.SPACE); 
            } 

            this.builder.Append(UriHelper.QUOTE); 
            this.builder.Append(this.TypeNameForUri(b.TypeOperand));
            this.builder.Append(UriHelper.QUOTE);
            this.builder.Append(UriHelper.RIGHTPAREN);
 
            return b;
        } 
 
        /// 
        /// ParameterExpression visit method. 
        /// 
        /// The ParameterExpression expression to visit
        /// The visited ParameterExpression expression 
        internal override Expression VisitParameter(ParameterExpression p) 
        {
            return p; 
        } 

        ///  
        /// References to the current input - the resource set - do not appear in the URL.
        /// 
        /// The expression to test
        /// true if the expression represents a reference to the current (resource set) input; otherwise false. 
        private static bool IsInputReference(Expression exp)
        { 
            return (exp is InputReferenceExpression || exp is ParameterExpression); 
        }
 
        /// Gets the type name to be used in the URI for the given .
        /// Type to get name for.
        /// The name for the , suitable for including in a URI.
        private string TypeNameForUri(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 
            type = Nullable.GetUnderlyingType(type) ?? type; 

            if (ClientConvert.IsKnownType(type)) 
            {
                if (ClientConvert.IsSupportedPrimitiveTypeForUri(type))
                {
                    return ClientConvert.ToTypeName(type); 
                }
 
                // unsupported primitive type 
                throw new NotSupportedException(Strings.ALinq_CantCastToUnsupportedPrimitive(type.Name));
            } 
            else
            {
                return this.context.ResolveNameFromType(type) ?? type.FullName;
            } 
        }
 
        ///  
        /// Visits operands for Binary and Unary expressions.
        /// Will only output parens if operand is complex expression, 
        /// this is so don't have unecessary parens in URI.
        /// 
        /// The operand expression to visit
        private void VisitOperand(Expression e) 
        {
            if (e is BinaryExpression || e is UnaryExpression) 
            { 
                this.builder.Append(UriHelper.LEFTPAREN);
                this.Visit(e); 
                this.builder.Append(UriHelper.RIGHTPAREN);
            }
            else
            { 
                this.Visit(e);
            } 
        } 

        ///  
        /// Serializes an expression to a string
        /// 
        /// Expression to serialize
        /// serialized expression 
        private string Translate(Expression e)
        { 
            this.Visit(e); 
            return this.builder.ToString();
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Serializes sub-expressions as query options in the URI.
//  
// 
// @owner  [....]
//--------------------------------------------------------------------- 

namespace System.Data.Services.Client
{
    #region Namespaces. 

    using System; 
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Linq.Expressions; 
    using System.Reflection;
    using System.Text;

    #endregion Namespaces. 

    ///  
    /// Special visitor to serialize supported expression as query parameters 
    /// in the generated URI.
    ///  
    internal class ExpressionWriter : DataServiceALinqExpressionVisitor
    {
        #region Private fields.
 
        /// Internal buffer.
        private readonly StringBuilder builder; 
 
        /// Data context used to generate type names for types.
        private readonly DataServiceContext context; 

        /// Stack of expressions being visited.
        private readonly Stack expressionStack;
 
        /// set if can't translate expression
        private bool cantTranslateExpression; 
 
        /// Parent expression of the current expression (expression.Peek()); possibly null.
        private Expression parent; 

        #endregion Private fields.

        ///  
        /// Creates an ExpressionWriter for the specified .
        ///  
        /// Data context used to generate type names for types. 
        private ExpressionWriter(DataServiceContext context)
        { 
            Debug.Assert(context != null, "context != null");
            this.context = context;
            this.builder = new StringBuilder();
            this.expressionStack = new Stack(); 
            this.expressionStack.Push(null);
        } 
 
        /// 
        /// Serializes an expression to a string 
        /// 
        /// Data context used to generate type names for types.
        /// Expression to serialize
        /// serialized expression 
        internal static string ExpressionToString(DataServiceContext context, Expression e)
        { 
            ExpressionWriter ew = new ExpressionWriter(context); 
            string serialized = ew.Translate(e);
            if (ew.cantTranslateExpression) 
            {
                throw new NotSupportedException(Strings.ALinq_CantTranslateExpression(e.ToString()));
            }
 
            return serialized;
        } 
 
        /// Main visit method.
        /// Expression to visit 
        /// Visited expression
        internal override Expression Visit(Expression exp)
        {
            this.parent = this.expressionStack.Peek(); 
            this.expressionStack.Push(exp);
            Expression result = base.Visit(exp); 
            this.expressionStack.Pop(); 
            return result;
        } 

        /// 
        /// ConditionalExpression visit method
        ///  
        /// The ConditionalExpression expression to visit
        /// The visited ConditionalExpression expression  
        internal override Expression VisitConditional(ConditionalExpression c) 
        {
            this.cantTranslateExpression = true; 
            return c;
        }

        ///  
        /// LambdaExpression visit method
        ///  
        /// The LambdaExpression to visit 
        /// The visited LambdaExpression
        internal override Expression VisitLambda(LambdaExpression lambda) 
        {
            this.cantTranslateExpression = true;
            return lambda;
        } 

        ///  
        /// NewExpression visit method 
        /// 
        /// The NewExpression to visit 
        /// The visited NewExpression
        internal override NewExpression VisitNew(NewExpression nex)
        {
            this.cantTranslateExpression = true; 
            return nex;
        } 
 
        /// 
        /// MemberInitExpression visit method 
        /// 
        /// The MemberInitExpression to visit
        /// The visited MemberInitExpression
        internal override Expression VisitMemberInit(MemberInitExpression init) 
        {
            this.cantTranslateExpression = true; 
            return init; 
        }
 
        /// 
        /// ListInitExpression visit method
        /// 
        /// The ListInitExpression to visit 
        /// The visited ListInitExpression
        internal override Expression VisitListInit(ListInitExpression init) 
        { 
            this.cantTranslateExpression = true;
            return init; 
        }

        /// 
        /// NewArrayExpression visit method 
        /// 
        /// The NewArrayExpression to visit 
        /// The visited NewArrayExpression 
        internal override Expression VisitNewArray(NewArrayExpression na)
        { 
            this.cantTranslateExpression = true;
            return na;
        }
 
        /// 
        /// InvocationExpression visit method 
        ///  
        /// The InvocationExpression to visit
        /// The visited InvocationExpression 
        internal override Expression VisitInvocation(InvocationExpression iv)
        {
            this.cantTranslateExpression = true;
            return iv; 
        }
 
        ///  
        /// Input resource set references are intentionally omitted from the URL string.
        ///  
        /// The input reference
        /// The same input reference expression
        internal override Expression VisitInputReferenceExpression(InputReferenceExpression ire)
        { 
            // This method intentionally does not write anything to the URI.
            // This is how 'Where(.Id == 5)' becomes '$filter=Id eq 5'. 
            Debug.Assert(ire != null, "ire != null"); 
            if (this.parent == null || this.parent.NodeType != ExpressionType.MemberAccess)
            { 
                // Ideally we refer to the parent expression as the un-translatable one,
                // because we cannot reference 'this' as a standalone expression; however
                // if the parent is null for any reasonn, we fall back to the expression itself.
                string expressionText = (this.parent != null) ? this.parent.ToString() : ire.ToString(); 
                throw new NotSupportedException(Strings.ALinq_CantTranslateExpression(expressionText));
            } 
 
            return ire;
        } 

        /// 
        /// MethodCallExpression visit method
        ///  
        /// The MethodCallExpression expression to visit
        /// The visited MethodCallExpression expression  
        internal override Expression VisitMethodCall(MethodCallExpression m) 
        {
            string methodName; 
            if (TypeSystem.TryGetQueryOptionMethod(m.Method, out methodName))
            {
                this.builder.Append(methodName);
                this.builder.Append(UriHelper.LEFTPAREN); 

                // There is a single function, 'substringof', which reorders its argument with 
                // respect to the CLR method. Thus handling it as a special case rather than 
                // using a more general argument reordering mechanism.
                if (methodName == "substringof") 
                {
                    Debug.Assert(m.Method.Name == "Contains", "m.Method.Name == 'Contains'");
                    Debug.Assert(m.Object != null, "m.Object != null");
                    Debug.Assert(m.Arguments.Count == 1, "m.Arguments.Count == 1"); 
                    this.Visit(m.Arguments[0]);
                    this.builder.Append(UriHelper.COMMA); 
                    this.Visit(m.Object); 
                }
                else 
                {
                    if (m.Object != null)
                    {
                        this.Visit(m.Object); 
                    }
 
                    if (m.Arguments.Count > 0) 
                    {
                        if (m.Object != null) 
                        {
                            this.builder.Append(UriHelper.COMMA);
                        }
 
                        for (int ii = 0; ii < m.Arguments.Count; ii++)
                        { 
                            this.Visit(m.Arguments[ii]); 
                            if (ii < m.Arguments.Count - 1)
                            { 
                                this.builder.Append(UriHelper.COMMA);
                            }
                        }
                    } 
                }
 
                this.builder.Append(UriHelper.RIGHTPAREN); 
            }
            else 
            {
                this.cantTranslateExpression = true;
            }
 
            return m;
        } 
 
        /// 
        /// Serializes an MemberExpression to a string 
        /// 
        /// Expression to serialize
        /// MemberExpression
        internal override Expression VisitMemberAccess(MemberExpression m) 
        {
            if (m.Member is FieldInfo) 
            { 
                throw new NotSupportedException(Strings.ALinq_CantReferToPublicField(m.Member.Name));
            } 

            Expression e = this.Visit(m.Expression);

            // if this is a Nullable instance, don't write out /Value since not supported by server 
            if (m.Member.Name == "Value" && m.Member.DeclaringType.IsGenericType
                && m.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>)) 
            { 
                return m;
            } 

            if (!IsInputReference(e))
            {
                this.builder.Append(UriHelper.FORWARDSLASH); 
            }
 
            this.builder.Append(m.Member.Name); 

            return m; 
        }

        /// 
        /// ConstantExpression visit method 
        /// 
        /// The ConstantExpression expression to visit 
        /// The visited ConstantExpression expression  
        internal override Expression VisitConstant(ConstantExpression c)
        { 
            string result = null;
            if (c.Value == null)
            {
                this.builder.Append(UriHelper.NULL); 
                return c;
            } 
            else if (!ClientConvert.TryKeyPrimitiveToString(c.Value, out result)) 
            {
                throw new InvalidOperationException(Strings.ALinq_CouldNotConvert(c.Value)); 
            }

            Debug.Assert(result != null, "result != null");
            this.builder.Append(System.Uri.EscapeDataString(result)); 
            return c;
        } 
 
        /// 
        /// Serializes an UnaryExpression to a string 
        /// 
        /// Expression to serialize
        /// UnaryExpression
        internal override Expression VisitUnary(UnaryExpression u) 
        {
            switch (u.NodeType) 
            { 
                case ExpressionType.Not:
                    this.builder.Append(UriHelper.NOT); 
                    this.builder.Append(UriHelper.SPACE);
                    this.VisitOperand(u.Operand);
                    break;
                case ExpressionType.Negate: 
                case ExpressionType.NegateChecked:
                    this.builder.Append(UriHelper.SPACE); 
                    this.builder.Append(UriHelper.NEGATE); 
                    this.VisitOperand(u.Operand);
                    break; 
                case ExpressionType.Convert:
                case ExpressionType.ConvertChecked:
                    if (u.Type != typeof(object))
                    { 
                        this.builder.Append(UriHelper.CAST);
                        this.builder.Append(UriHelper.LEFTPAREN); 
                        if (!IsInputReference(u.Operand)) 
                        {
                            this.Visit(u.Operand); 
                            this.builder.Append(UriHelper.COMMA);
                        }

                        this.builder.Append(UriHelper.QUOTE); 
                        this.builder.Append(this.TypeNameForUri(u.Type));
                        this.builder.Append(UriHelper.QUOTE); 
                        this.builder.Append(UriHelper.RIGHTPAREN); 
                    }
                    else 
                    {
                        if (!IsInputReference(u.Operand))
                        {
                            this.Visit(u.Operand); 
                        }
                    } 
 
                    break;
                case ExpressionType.UnaryPlus: 
                    // no-op always ignore.
                    break;
                default:
                    this.cantTranslateExpression = true; 
                    break;
            } 
 
            return u;
        } 

        /// 
        /// Serializes an BinaryExpression to a string
        ///  
        /// BinaryExpression to serialize
        /// serialized expression 
        internal override Expression VisitBinary(BinaryExpression b) 
        {
            this.VisitOperand(b.Left); 
            this.builder.Append(UriHelper.SPACE);
            switch (b.NodeType)
            {
                case ExpressionType.AndAlso: 
                case ExpressionType.And:
                    this.builder.Append(UriHelper.AND); 
                    break; 
                case ExpressionType.OrElse:
                case ExpressionType.Or: 
                    this.builder.Append(UriHelper.OR);
                    break;
                case ExpressionType.Equal:
                    this.builder.Append(UriHelper.EQ); 
                    break;
                case ExpressionType.NotEqual: 
                    this.builder.Append(UriHelper.NE); 
                    break;
                case ExpressionType.LessThan: 
                    this.builder.Append(UriHelper.LT);
                    break;
                case ExpressionType.LessThanOrEqual:
                    this.builder.Append(UriHelper.LE); 
                    break;
                case ExpressionType.GreaterThan: 
                    this.builder.Append(UriHelper.GT); 
                    break;
                case ExpressionType.GreaterThanOrEqual: 
                    this.builder.Append(UriHelper.GE);
                    break;
                case ExpressionType.Add:
                case ExpressionType.AddChecked: 
                    this.builder.Append(UriHelper.ADD);
                    break; 
                case ExpressionType.Subtract: 
                case ExpressionType.SubtractChecked:
                    this.builder.Append(UriHelper.SUB); 
                    break;
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    this.builder.Append(UriHelper.MUL); 
                    break;
                case ExpressionType.Divide: 
                    this.builder.Append(UriHelper.DIV); 
                    break;
                case ExpressionType.Modulo: 
                    this.builder.Append(UriHelper.MOD);
                    break;
                case ExpressionType.ArrayIndex:
                case ExpressionType.Power: 
                case ExpressionType.Coalesce:
                case ExpressionType.ExclusiveOr: 
                case ExpressionType.LeftShift: 
                case ExpressionType.RightShift:
                default: 
                    this.cantTranslateExpression = true;
                    break;
            }
 
            this.builder.Append(UriHelper.SPACE);
            this.VisitOperand(b.Right); 
            return b; 
        }
 
        /// 
        /// Serializes an TypeBinaryExpression to a string
        /// 
        /// TypeBinaryExpression to serialize 
        /// serialized expression
        internal override Expression VisitTypeIs(TypeBinaryExpression b) 
        { 
            this.builder.Append(UriHelper.ISOF);
            this.builder.Append(UriHelper.LEFTPAREN); 

            if (!IsInputReference(b.Expression))
            {
                this.Visit(b.Expression); 
                this.builder.Append(UriHelper.COMMA);
                this.builder.Append(UriHelper.SPACE); 
            } 

            this.builder.Append(UriHelper.QUOTE); 
            this.builder.Append(this.TypeNameForUri(b.TypeOperand));
            this.builder.Append(UriHelper.QUOTE);
            this.builder.Append(UriHelper.RIGHTPAREN);
 
            return b;
        } 
 
        /// 
        /// ParameterExpression visit method. 
        /// 
        /// The ParameterExpression expression to visit
        /// The visited ParameterExpression expression 
        internal override Expression VisitParameter(ParameterExpression p) 
        {
            return p; 
        } 

        ///  
        /// References to the current input - the resource set - do not appear in the URL.
        /// 
        /// The expression to test
        /// true if the expression represents a reference to the current (resource set) input; otherwise false. 
        private static bool IsInputReference(Expression exp)
        { 
            return (exp is InputReferenceExpression || exp is ParameterExpression); 
        }
 
        /// Gets the type name to be used in the URI for the given .
        /// Type to get name for.
        /// The name for the , suitable for including in a URI.
        private string TypeNameForUri(Type type) 
        {
            Debug.Assert(type != null, "type != null"); 
            type = Nullable.GetUnderlyingType(type) ?? type; 

            if (ClientConvert.IsKnownType(type)) 
            {
                if (ClientConvert.IsSupportedPrimitiveTypeForUri(type))
                {
                    return ClientConvert.ToTypeName(type); 
                }
 
                // unsupported primitive type 
                throw new NotSupportedException(Strings.ALinq_CantCastToUnsupportedPrimitive(type.Name));
            } 
            else
            {
                return this.context.ResolveNameFromType(type) ?? type.FullName;
            } 
        }
 
        ///  
        /// Visits operands for Binary and Unary expressions.
        /// Will only output parens if operand is complex expression, 
        /// this is so don't have unecessary parens in URI.
        /// 
        /// The operand expression to visit
        private void VisitOperand(Expression e) 
        {
            if (e is BinaryExpression || e is UnaryExpression) 
            { 
                this.builder.Append(UriHelper.LEFTPAREN);
                this.Visit(e); 
                this.builder.Append(UriHelper.RIGHTPAREN);
            }
            else
            { 
                this.Visit(e);
            } 
        } 

        ///  
        /// Serializes an expression to a string
        /// 
        /// Expression to serialize
        /// serialized expression 
        private string Translate(Expression e)
        { 
            this.Visit(e); 
            return this.builder.ToString();
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK