ClosureBinding.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / ClosureBinding.cs / 3 / ClosureBinding.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
//--------------------------------------------------------------------- 
 
using System.Collections;
using LinqExpression = System.Linq.Expressions.Expression; 
using CqtExpression = System.Data.Common.CommandTrees.DbExpression;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq.Expressions; 
using System.Data.Common.Utils;
using System.Data.Common.CommandTrees; 
using System.Globalization; 
using System.Data.Metadata.Edm;
using System.Reflection; 
using System.Linq;
using System.Threading;
namespace System.Data.Objects.ELinq
{ 
    /// 
    /// Binding between an object parameter or sub-query and LINQ expression that needs to be 
    /// re-evaluated before executing a query because it is part of the closure. 
    ///
    /// Invariants: the binding defines either the Parameter or the Query property, not both. 
    /// 
    internal abstract class ClosureBinding
    {
        #region Constructors 
        private ClosureBinding(LinqExpression sourceExpression)
        { 
            _sourceExpression = sourceExpression; 
        }
        #endregion 

        #region Fields
        private readonly LinqExpression _sourceExpression;
        private static readonly string s_parameterPrefix = "p__linq__"; 
        private static long s_parameterNumber;
        #endregion 
 
        #region Properties
        ///  
        /// Gets the query produced by this closure expression. Returns null if no
        /// query is produced.
        /// 
        internal abstract ObjectQuery Query { get; } 

        ///  
        /// Gets the expression produced by this closure expression. Returns null if no 
        /// expression is produced.
        ///  
        internal abstract LinqExpression Expression { get; }

        /// 
        /// Gets the parameter storing the primitive value produced by this closure expression. 
        /// Returns null if no primitive value is produced.
        ///  
        internal abstract ObjectParameter Parameter { get; } 
        #endregion
 
        #region Methods
        /// 
        /// Evaluates the binding and populates the object parameter value.
        ///  
        /// true if the entire expression should be re-evaluated (if a sub-expression has changed);
        /// false otherwise 
        internal abstract bool EvaluateBinding(); 

        internal abstract ClosureBinding CopyToContext(ExpressionConverter context); 


        internal static bool TryGetTypeUsageForObjectParameter(ObjectParameter parameter, ClrPerspective perspective, out TypeUsage typeUsage)
        { 
            // since ObjectParameters do not allow users to especify 'facets', make
            // sure that the parameter typeusage is not populated with the provider 
            // dafault facet values 
            if (perspective.TryGetTypeByName(parameter.MappableType.FullName,
                false, // bIgnoreCase 
                out typeUsage) &&
                TypeSemantics.IsPrimitiveType(typeUsage))
            {
                return true; 
            }
 
            typeUsage = null; 
            return false;
        } 

        /// 
        /// requires: expression must not be null
        /// Attempt to treat the given expression as a supported parameter reference in a closure. 
        /// Succeeds if the pattern of the expression is precisely Member(Constant), and the member
        /// is of primitive type. 
        ///  
        /// Expression to check.
        /// Perspective to use to resolve expression type. 
        /// Determines whether Lambda sub-expressions are permitted in this context.
        /// Closure binding corresponding to the given expression.
        /// Type usage for the binding.
        /// true if the given expression can be bound 
        internal static bool TryCreateClosureBinding(LinqExpression expression,
            ClrPerspective perspective, bool allowLambda, HashSet closureCandidates, out ClosureBinding binding, out TypeUsage typeUsage) 
        { 
            Debug.Assert(null != expression);
            if (ExpressionEvaluator.IsExpressionNodeAClosure(expression) && 
                closureCandidates.Contains(expression))  // all nodes below it must qualify also
            {
                ObjectParameter parameter = new ObjectParameter(GenerateParameterName(),
                    expression.Type); 

                if(TryGetTypeUsageForObjectParameter(parameter, perspective, out typeUsage)) 
                { 
                    binding = new ParameterBinding(expression, parameter);
 
                    // compute the parameter value during translation since we translate directly
                    // before evaluating (in other words, the value of the parameter will not change
                    // between now and the time results are produced)
                    binding.EvaluateBinding(); 
                    return true;
                } 
 
                // determine if the expression yields an inline ObjectQuery or Expression
                object result = ExpressionEvaluator.EvaluateExpression(expression); 
                ObjectQuery resultQuery = result as ObjectQuery;
                if (resultQuery != null)
                {
                    binding = new NestedLogicBinding(expression, result, resultQuery.QueryState.UserSpecifiedMergeOption); 
                    return true;
                } 
                else if (allowLambda && result is LambdaExpression) 
                {
                    binding = new NestedLogicBinding(expression, result, null); 
                    return true;
                }
            }
            // doesn't match the pattern 
            binding = null;
            typeUsage = null; 
            return false; 
        }
 

        internal static string GenerateParameterName()
        {
            // To avoid collisions with user parameters (the full set is not 
            // known at this time) we plug together an 'unlikely' prefix and
            // a number. 
            return String.Format(CultureInfo.InvariantCulture, "{0}{1}", 
                s_parameterPrefix,
                Interlocked.Increment(ref s_parameterNumber)); 
        }
        #endregion

        #region Nested types 
        private class NestedLogicBinding : ClosureBinding
        { 
            private MergeOption? _mergeOption; 

            internal NestedLogicBinding(LinqExpression sourceExpression, object nestedLogic, MergeOption? mergeOption) 
                : base(sourceExpression)
            {
                _nestedLogic = nestedLogic;
                _mergeOption = mergeOption; 
            }
 
            private object _nestedLogic; 

            internal override ClosureBinding CopyToContext(ExpressionConverter context) 
            {
                return this;
            }
 
            internal override bool EvaluateBinding()
            { 
                // must recompile entire expression if the sub-expression has changed 
                object currentLogic = ExpressionEvaluator.EvaluateExpression(_sourceExpression);
                if (object.ReferenceEquals(_nestedLogic, currentLogic)) 
                {
                    // The instances are the same; however, if the nested logic is actually
                    // an instance of ObjectQuery, then any mutable properties on the instance
                    // may also have changed. Currently only MergeOption is significant, so it 
                    // must be compared here.
                    ObjectQuery query = currentLogic as ObjectQuery; 
                    if (query == null) 
                    {
                        // The nested logic is not an ObjectQuery; simply return false. 
                        return false;
                    }

                    // The only way the merge option can change in a way that affects us 
                    // here is if it has been explicitly set using ObjectQuery.MergeOption.
                    MergeOption? newMergeOption = query.QueryState.UserSpecifiedMergeOption; 
 
                    if (!newMergeOption.HasValue && !_mergeOption.HasValue)
                    { 
                        // No difference.
                        return false;
                    }
 
                    if (newMergeOption.HasValue && _mergeOption.HasValue &&
                        newMergeOption.Value == _mergeOption.Value) 
                    { 
                        // No difference.
                        return false; 
                    }
                }

                return true; 
            }
 
            internal override LinqExpression Expression 
            {
                get { return _nestedLogic as LinqExpression; } 
            }

            internal override ObjectQuery Query
            { 
                get { return _nestedLogic as ObjectQuery; }
            } 
 
            internal override ObjectParameter Parameter
            { 
                get { return null; }
            }
        }
 
        private class ParameterBinding : ClosureBinding
        { 
            internal ParameterBinding(LinqExpression sourceExpression, ObjectParameter parameter) 
                : base(sourceExpression)
            { 
                _parameter = parameter;
            }

            private ObjectParameter _parameter; 

            internal override ClosureBinding CopyToContext(ExpressionConverter context) 
            { 
                ObjectParameter targetParameter = null;
                if (context.Parameters != null) 
                {
                    targetParameter = context.Parameters[_parameter.Name];
                }
 
                return new ParameterBinding(_sourceExpression, targetParameter);
            } 
 
            internal override bool EvaluateBinding()
            { 
                object currentValue = ExpressionEvaluator.EvaluateExpression(_sourceExpression);
                _parameter.Value = currentValue;
                return false;
            } 

            internal override LinqExpression Expression 
            { 
                get { return null; }
            } 

            internal override ObjectQuery Query
            {
                get { return null; } 
            }
 
            internal override ObjectParameter Parameter 
            {
                get { return _parameter; } 
            }
        }

        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
//--------------------------------------------------------------------- 
 
using System.Collections;
using LinqExpression = System.Linq.Expressions.Expression; 
using CqtExpression = System.Data.Common.CommandTrees.DbExpression;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq.Expressions; 
using System.Data.Common.Utils;
using System.Data.Common.CommandTrees; 
using System.Globalization; 
using System.Data.Metadata.Edm;
using System.Reflection; 
using System.Linq;
using System.Threading;
namespace System.Data.Objects.ELinq
{ 
    /// 
    /// Binding between an object parameter or sub-query and LINQ expression that needs to be 
    /// re-evaluated before executing a query because it is part of the closure. 
    ///
    /// Invariants: the binding defines either the Parameter or the Query property, not both. 
    /// 
    internal abstract class ClosureBinding
    {
        #region Constructors 
        private ClosureBinding(LinqExpression sourceExpression)
        { 
            _sourceExpression = sourceExpression; 
        }
        #endregion 

        #region Fields
        private readonly LinqExpression _sourceExpression;
        private static readonly string s_parameterPrefix = "p__linq__"; 
        private static long s_parameterNumber;
        #endregion 
 
        #region Properties
        ///  
        /// Gets the query produced by this closure expression. Returns null if no
        /// query is produced.
        /// 
        internal abstract ObjectQuery Query { get; } 

        ///  
        /// Gets the expression produced by this closure expression. Returns null if no 
        /// expression is produced.
        ///  
        internal abstract LinqExpression Expression { get; }

        /// 
        /// Gets the parameter storing the primitive value produced by this closure expression. 
        /// Returns null if no primitive value is produced.
        ///  
        internal abstract ObjectParameter Parameter { get; } 
        #endregion
 
        #region Methods
        /// 
        /// Evaluates the binding and populates the object parameter value.
        ///  
        /// true if the entire expression should be re-evaluated (if a sub-expression has changed);
        /// false otherwise 
        internal abstract bool EvaluateBinding(); 

        internal abstract ClosureBinding CopyToContext(ExpressionConverter context); 


        internal static bool TryGetTypeUsageForObjectParameter(ObjectParameter parameter, ClrPerspective perspective, out TypeUsage typeUsage)
        { 
            // since ObjectParameters do not allow users to especify 'facets', make
            // sure that the parameter typeusage is not populated with the provider 
            // dafault facet values 
            if (perspective.TryGetTypeByName(parameter.MappableType.FullName,
                false, // bIgnoreCase 
                out typeUsage) &&
                TypeSemantics.IsPrimitiveType(typeUsage))
            {
                return true; 
            }
 
            typeUsage = null; 
            return false;
        } 

        /// 
        /// requires: expression must not be null
        /// Attempt to treat the given expression as a supported parameter reference in a closure. 
        /// Succeeds if the pattern of the expression is precisely Member(Constant), and the member
        /// is of primitive type. 
        ///  
        /// Expression to check.
        /// Perspective to use to resolve expression type. 
        /// Determines whether Lambda sub-expressions are permitted in this context.
        /// Closure binding corresponding to the given expression.
        /// Type usage for the binding.
        /// true if the given expression can be bound 
        internal static bool TryCreateClosureBinding(LinqExpression expression,
            ClrPerspective perspective, bool allowLambda, HashSet closureCandidates, out ClosureBinding binding, out TypeUsage typeUsage) 
        { 
            Debug.Assert(null != expression);
            if (ExpressionEvaluator.IsExpressionNodeAClosure(expression) && 
                closureCandidates.Contains(expression))  // all nodes below it must qualify also
            {
                ObjectParameter parameter = new ObjectParameter(GenerateParameterName(),
                    expression.Type); 

                if(TryGetTypeUsageForObjectParameter(parameter, perspective, out typeUsage)) 
                { 
                    binding = new ParameterBinding(expression, parameter);
 
                    // compute the parameter value during translation since we translate directly
                    // before evaluating (in other words, the value of the parameter will not change
                    // between now and the time results are produced)
                    binding.EvaluateBinding(); 
                    return true;
                } 
 
                // determine if the expression yields an inline ObjectQuery or Expression
                object result = ExpressionEvaluator.EvaluateExpression(expression); 
                ObjectQuery resultQuery = result as ObjectQuery;
                if (resultQuery != null)
                {
                    binding = new NestedLogicBinding(expression, result, resultQuery.QueryState.UserSpecifiedMergeOption); 
                    return true;
                } 
                else if (allowLambda && result is LambdaExpression) 
                {
                    binding = new NestedLogicBinding(expression, result, null); 
                    return true;
                }
            }
            // doesn't match the pattern 
            binding = null;
            typeUsage = null; 
            return false; 
        }
 

        internal static string GenerateParameterName()
        {
            // To avoid collisions with user parameters (the full set is not 
            // known at this time) we plug together an 'unlikely' prefix and
            // a number. 
            return String.Format(CultureInfo.InvariantCulture, "{0}{1}", 
                s_parameterPrefix,
                Interlocked.Increment(ref s_parameterNumber)); 
        }
        #endregion

        #region Nested types 
        private class NestedLogicBinding : ClosureBinding
        { 
            private MergeOption? _mergeOption; 

            internal NestedLogicBinding(LinqExpression sourceExpression, object nestedLogic, MergeOption? mergeOption) 
                : base(sourceExpression)
            {
                _nestedLogic = nestedLogic;
                _mergeOption = mergeOption; 
            }
 
            private object _nestedLogic; 

            internal override ClosureBinding CopyToContext(ExpressionConverter context) 
            {
                return this;
            }
 
            internal override bool EvaluateBinding()
            { 
                // must recompile entire expression if the sub-expression has changed 
                object currentLogic = ExpressionEvaluator.EvaluateExpression(_sourceExpression);
                if (object.ReferenceEquals(_nestedLogic, currentLogic)) 
                {
                    // The instances are the same; however, if the nested logic is actually
                    // an instance of ObjectQuery, then any mutable properties on the instance
                    // may also have changed. Currently only MergeOption is significant, so it 
                    // must be compared here.
                    ObjectQuery query = currentLogic as ObjectQuery; 
                    if (query == null) 
                    {
                        // The nested logic is not an ObjectQuery; simply return false. 
                        return false;
                    }

                    // The only way the merge option can change in a way that affects us 
                    // here is if it has been explicitly set using ObjectQuery.MergeOption.
                    MergeOption? newMergeOption = query.QueryState.UserSpecifiedMergeOption; 
 
                    if (!newMergeOption.HasValue && !_mergeOption.HasValue)
                    { 
                        // No difference.
                        return false;
                    }
 
                    if (newMergeOption.HasValue && _mergeOption.HasValue &&
                        newMergeOption.Value == _mergeOption.Value) 
                    { 
                        // No difference.
                        return false; 
                    }
                }

                return true; 
            }
 
            internal override LinqExpression Expression 
            {
                get { return _nestedLogic as LinqExpression; } 
            }

            internal override ObjectQuery Query
            { 
                get { return _nestedLogic as ObjectQuery; }
            } 
 
            internal override ObjectParameter Parameter
            { 
                get { return null; }
            }
        }
 
        private class ParameterBinding : ClosureBinding
        { 
            internal ParameterBinding(LinqExpression sourceExpression, ObjectParameter parameter) 
                : base(sourceExpression)
            { 
                _parameter = parameter;
            }

            private ObjectParameter _parameter; 

            internal override ClosureBinding CopyToContext(ExpressionConverter context) 
            { 
                ObjectParameter targetParameter = null;
                if (context.Parameters != null) 
                {
                    targetParameter = context.Parameters[_parameter.Name];
                }
 
                return new ParameterBinding(_sourceExpression, targetParameter);
            } 
 
            internal override bool EvaluateBinding()
            { 
                object currentValue = ExpressionEvaluator.EvaluateExpression(_sourceExpression);
                _parameter.Value = currentValue;
                return false;
            } 

            internal override LinqExpression Expression 
            { 
                get { return null; }
            } 

            internal override ObjectQuery Query
            {
                get { return null; } 
            }
 
            internal override ObjectParameter Parameter 
            {
                get { return _parameter; } 
            }
        }

        #endregion 
    }
} 

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