InputBinder.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

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

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//  
//      Expression visitor that converts ParameterReference or (MemberAccess*)\ParameterReference expressions
//      into references to one or more ResourceSetExpressions. After processing, the specified expression tree 
//      will contain InputReferenceExpressions instead of these parameter or parameter and property references. 
// 
// 
// @owner  [....]
//---------------------------------------------------------------------

namespace System.Data.Services.Client 
{
    #region Namespaces. 
 
    using System;
    using System.Collections.Generic; 
    using System.Diagnostics;
    using System.Linq.Expressions;
    using System.Reflection;
 
    #endregion Namespaces.
 
    ///  
    /// Replaces references to resource sets - represented as either ParameterExpressions or one or more
    /// MemberExpressions over a ParameterExpression - with an appropriate InputReferenceExpression that 
    /// indicates which resource set is referenced; effective 'binds' the argument expression to the
    /// resource sets that it references.
    /// 
    internal sealed class InputBinder : DataServiceALinqExpressionVisitor 
    {
        #region Private fields. 
 
        /// Tracks which resource sets are referenced by the argument expression
        private readonly HashSet referencedInputs = new HashSet(EqualityComparer.Default); 

        /// Resource from which valid references must start; if no set with a transparent scope is present, only direct references to this resource will be rebound
        private readonly ResourceExpression input;
 
        /// The input resource, as a resource set (may be null if the input is actually a NavigationPropertySingletonExpression)
        private readonly ResourceSetExpression inputSet; 
 
        /// The ParameterExpression that, if encountered, indicates a reference to the input resource set
        private readonly ParameterExpression inputParameter; 

        #endregion Private fields.

        ///  
        /// Constructs a new InputBinder based on the specified input resource set, which is represented by the specified ParameterExpression.
        ///  
        /// The current input resource from which valid references must start 
        /// The parameter that must be referenced in order to refer to the specified input resource set
        private InputBinder(ResourceExpression resource, ParameterExpression setReferenceParam) 
        {
            this.input = resource;
            this.inputSet = resource as ResourceSetExpression;
            this.inputParameter = setReferenceParam; 
        }
 
        ///  
        /// Replaces Lambda parameter references or transparent scope property accesses over those Lambda
        /// parameter references with s to the appropriate corresponding 
        /// s, based on the 'input' ResourceSetExpression to which the
        /// Lambda is logically applied and any enclosing transparent scope applied to that input resource set.
        /// 
        /// The expression to rebind 
        /// 
        /// The 'current input' resource set - either the root resource set or the 
        /// rightmost set in the navigation chain. 
        /// The Lambda parameter that represents a reference to the 'input' set
        /// A list that will be populated with the resource sets that were referenced by the rebound expression 
        /// 
        /// The rebound version of  where MemberExpression/ParameterExpressions that
        /// represent resource set references have been replaced with appropriate InputReferenceExpressions.
        ///  
        internal static Expression Bind(Expression e, ResourceExpression currentInput, ParameterExpression inputParameter, List referencedInputs)
        { 
            Debug.Assert(e != null, "Expression cannot be null"); 
            Debug.Assert(currentInput != null, "A current input resource set is required");
            Debug.Assert(inputParameter != null, "The input lambda parameter is required"); 
            Debug.Assert(referencedInputs != null, "The referenced inputs list is required");

            InputBinder binder = new InputBinder(currentInput, inputParameter);
            Expression result = binder.Visit(e); 
            referencedInputs.AddRange(binder.referencedInputs);
            return result; 
        } 

        ///  
        /// Resolves member accesses that represent transparent scope property accesses to the corresponding resource set,
        /// iff the input resource set is enclosed in a transparent scope and the specified MemberExpression represents
        /// such a property access.
        ///  
        /// MemberExpression expression to visit
        ///  
        /// An InputReferenceExpression if the member access represents a transparent scope property 
        /// access that can be resolved to a resource set in the path that produces the input resource set;
        /// otherwise the same MemberExpression is returned. 
        /// 
        internal override Expression VisitMemberAccess(MemberExpression m)
        {
            // If the current input resource set is not enclosed in a transparent scope, then this 
            // MemberExpression cannot represent a valid transparent scope access based on the input parameter.
            if (this.inputSet == null || 
                !this.inputSet.HasTransparentScope) 
            {
                return base.VisitMemberAccess(m); 
            }

            ParameterExpression innerParamRef = null;
            Stack nestedAccesses = new Stack(); 
            MemberExpression memberRef = m;
            while (memberRef != null && 
                   memberRef.Member.MemberType == MemberTypes.Property && 
                   memberRef.Expression != null)
            { 
                nestedAccesses.Push((PropertyInfo)memberRef.Member);

                if (memberRef.Expression.NodeType == ExpressionType.Parameter)
                { 
                    innerParamRef = (ParameterExpression)memberRef.Expression;
                } 
 
                memberRef = memberRef.Expression as MemberExpression;
            } 

            // Only continue if the inner non-MemberExpression is the input reference ParameterExpression and
            // at least one property reference is present - otherwise this cannot be a transparent scope access.
            if (innerParamRef != this.inputParameter || nestedAccesses.Count == 0) 
            {
                return m; 
            } 

            ResourceExpression target = this.input; 
            ResourceSetExpression targetSet = this.inputSet;
            bool transparentScopeTraversed = false;

            // Process all the traversals through transparent scopes. 
            while (nestedAccesses.Count > 0)
            { 
                if (targetSet == null || !targetSet.HasTransparentScope) 
                {
                    break; 
                }

                // Peek the property; pop it once it's consumed
                // (it could be a non-transparent-identifier access). 
                PropertyInfo currentProp = nestedAccesses.Peek();
 
                // If this is the accessor for the target, then the member 
                // refers to the target itself.
                if (currentProp.Name.Equals(targetSet.TransparentScope.Accessor, StringComparison.Ordinal)) 
                {
                    target = targetSet;
                    nestedAccesses.Pop();
                    transparentScopeTraversed = true; 
                    continue;
                } 
 
                // This member could also be one of the in-scope sources of the target.
                Expression source; 
                if (!targetSet.TransparentScope.SourceAccessors.TryGetValue(currentProp.Name, out source))
                {
                    break;
                } 

                transparentScopeTraversed = true; 
                nestedAccesses.Pop(); 
                Debug.Assert(source != null, "source != null -- otherwise ResourceBinder created an accessor to nowhere");
                InputReferenceExpression sourceReference = source as InputReferenceExpression; 
                if (sourceReference == null)
                {
                    targetSet = source as ResourceSetExpression;
                    if (targetSet == null || !targetSet.HasTransparentScope) 
                    {
                        target = (ResourceExpression)source; 
                    } 
                }
                else 
                {
                    targetSet = sourceReference.Target as ResourceSetExpression;
                    target = targetSet;
                } 
            }
 
            // If no traversals were made, the original expression is OK. 
            if (!transparentScopeTraversed)
            { 
                return m;
            }

            // Process traversals after the transparent scope. 
            Expression result = this.CreateReference(target);
            while (nestedAccesses.Count > 0) 
            { 
                result = Expression.Property(result, nestedAccesses.Pop());
            } 

            return result;
        }
 
        /// 
        /// Converts a parameter reference to the input resource set into an InputReferenceExpression, 
        /// iff the parameter reference is to the parameter expression that represents the input resource set 
        /// and the input resource set is not enclosed in a transparent scope.
        ///  
        /// The parameter reference expression
        /// 
        /// An InputReferenceExpression if the parameter reference is to the input parameter;
        /// otherwise the same parameter reference expression 
        /// 
        internal override Expression VisitParameter(ParameterExpression p) 
        { 
            // If the input Resource Set is not enclosed in a transparent scope,
            // and the parameter reference is a reference to the Lambda parameter 
            // that represents the input resource set, then return an InputReferenceExpression.
            if ((this.inputSet == null || !this.inputSet.HasTransparentScope) &&
               p == this.inputParameter)
            { 
                return this.CreateReference(this.input);
            } 
            else 
            {
                return base.VisitParameter(p); 
            }
        }

        ///  
        /// Returns an  that references the specified resource set,
        /// and also adds the the resource set to the hashset of resource sets that were referenced by the 
        /// expression that is being rebound. 
        /// 
        /// The resource(set) for which a reference was found 
        /// An InputReferenceExpression that represents a reference to the specified resource set
        private Expression CreateReference(ResourceExpression resource)
        {
            this.referencedInputs.Add(resource); 
            return resource.CreateReference();
        } 
    } 
}
 

// 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