DynamicMetaObjectBinder.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 / Core / Microsoft / Scripting / Actions / DynamicMetaObjectBinder.cs / 1305376 / DynamicMetaObjectBinder.cs

                            /* **************************************************************************** 
 *
 * Copyright (c) Microsoft Corporation.
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 * 
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/ 

using System.Collections.ObjectModel; 
using System.Diagnostics; 
using System.Dynamic.Utils;
using System.Linq.Expressions; 
using System.Linq.Expressions.Compiler;
using System.Runtime.CompilerServices;

#if SILVERLIGHT 
using System.Core;
#else 
using System.Runtime.Remoting; 
#endif
 
namespace System.Dynamic {
    /// 
    /// The dynamic call site binder that participates in the  binding protocol.
    ///  
    /// 
    /// The  performs the binding of the dynamic operation using the runtime values 
    /// as input. On the other hand, the  participates in the  
    /// binding protocol.
    ///  
    public abstract class DynamicMetaObjectBinder : CallSiteBinder {

        #region Public APIs
 
        /// 
        /// Initializes a new instance of the  class. 
        ///  
        protected DynamicMetaObjectBinder() {
        } 

        /// 
        /// The result type of the operation.
        ///  
        public virtual Type ReturnType {
            get { return typeof(object); } 
        } 

        ///  
        /// Performs the runtime binding of the dynamic operation on a set of arguments.
        /// 
        /// An array of arguments to the dynamic operation.
        /// The array of  instances that represent the parameters of the call site in the binding process. 
        /// A LabelTarget used to return the result of the dynamic binding.
        ///  
        /// An Expression that performs tests on the dynamic operation arguments, and 
        /// performs the dynamic operation if hte tests are valid. If the tests fail on
        /// subsequent occurrences of the dynamic operation, Bind will be called again 
        /// to produce a new  for the new argument types.
        /// 
        public sealed override Expression Bind(object[] args, ReadOnlyCollection parameters, LabelTarget returnLabel) {
            ContractUtils.RequiresNotNull(args, "args"); 
            ContractUtils.RequiresNotNull(parameters, "parameters");
            ContractUtils.RequiresNotNull(returnLabel, "returnLabel"); 
            if (args.Length == 0) { 
                throw Error.OutOfRange("args.Length", 1);
            } 
            if (parameters.Count == 0) {
                throw Error.OutOfRange("parameters.Count", 1);
            }
            if (args.Length != parameters.Count) { 
                throw new ArgumentOutOfRangeException("args");
            } 
 
            // Ensure that the binder's ReturnType matches CallSite's return
            // type. We do this so meta objects and language binders can 
            // compose trees together without needing to insert converts.
            Type expectedResult;
            if (IsStandardBinder) {
                expectedResult = ReturnType; 

                if (returnLabel.Type != typeof(void) && 
                    !TypeUtils.AreReferenceAssignable(returnLabel.Type, expectedResult)) { 
                    throw Error.BinderNotCompatibleWithCallSite(expectedResult, this, returnLabel.Type);
                } 
            } else {
                // Even for non-standard binders, we have to at least make sure
                // it works with the CallSite's type to build the return.
                expectedResult = returnLabel.Type; 
            }
 
            DynamicMetaObject target = DynamicMetaObject.Create(args[0], parameters[0]); 
            DynamicMetaObject[] metaArgs = CreateArgumentMetaObjects(args, parameters);
 
            DynamicMetaObject binding = Bind(target, metaArgs);

            if (binding == null) {
                throw Error.BindingCannotBeNull(); 
            }
 
            Expression body = binding.Expression; 
            BindingRestrictions restrictions = binding.Restrictions;
 
            // Ensure the result matches the expected result type.
            if (expectedResult != typeof(void) &&
                !TypeUtils.AreReferenceAssignable(expectedResult, body.Type)) {
 
                //
                // Blame the last person that handled the result: assume it's 
                // the dynamic object (if any), otherwise blame the language. 
                //
                if (target.Value is IDynamicMetaObjectProvider) { 
                    throw Error.DynamicObjectResultNotAssignable(body.Type, target.Value.GetType(), this, expectedResult);
                } else {
                    throw Error.DynamicBinderResultNotAssignable(body.Type, this, expectedResult);
                } 
            }
 
            // if the target is IDO, standard binders ask it to bind the rule so we may have a target-specific binding. 
            // it makes sense to restrict on the target's type in such cases.
            // ideally IDO metaobjects should do this, but they often miss that type of "this" is significant. 
            if (IsStandardBinder && args[0] as IDynamicMetaObjectProvider != null) {
                if (restrictions == BindingRestrictions.Empty) {
                    throw Error.DynamicBindingNeedsRestrictions(target.Value.GetType(), this);
                } 
            }
 
            restrictions = AddRemoteObjectRestrictions(restrictions, args, parameters); 

            // Add the return 
            if (body.NodeType != ExpressionType.Goto) {
                body = Expression.Return(returnLabel, body);
            }
 
            // Finally, add restrictions
            if (restrictions != BindingRestrictions.Empty) { 
                body = Expression.IfThen(restrictions.ToExpression(), body); 
            }
 
            return body;
        }

        private static DynamicMetaObject[] CreateArgumentMetaObjects(object[] args, ReadOnlyCollection parameters) { 
            DynamicMetaObject[] mos;
            if (args.Length != 1) { 
                mos = new DynamicMetaObject[args.Length - 1]; 
                for (int i = 1; i < args.Length; i++) {
                    mos[i - 1] = DynamicMetaObject.Create(args[i], parameters[i]); 
                }
            } else {
                mos = DynamicMetaObject.EmptyMetaObjects;
            } 
            return mos;
        } 
 
        private static BindingRestrictions AddRemoteObjectRestrictions(BindingRestrictions restrictions, object[] args, ReadOnlyCollection parameters) {
#if !SILVERLIGHT 

            for (int i = 0; i < parameters.Count; i++) {
                var expr = parameters[i];
                var value = args[i] as MarshalByRefObject; 

                // special case for MBR objects. 
                // when MBR objects are remoted they can have different conversion behavior 
                // so bindings created for local and remote objects should not be mixed.
                if (value != null && !IsComObject(value)) { 
                    BindingRestrictions remotedRestriction;
                    if (RemotingServices.IsObjectOutOfAppDomain(value)) {
                        remotedRestriction = BindingRestrictions.GetExpressionRestriction(
                            Expression.AndAlso( 
                                Expression.NotEqual(expr, Expression.Constant(null)),
                                Expression.Call( 
                                    typeof(RemotingServices).GetMethod("IsObjectOutOfAppDomain"), 
                                    expr
                                ) 
                            )
                        );
                    } else {
                        remotedRestriction = BindingRestrictions.GetExpressionRestriction( 
                            Expression.AndAlso(
                                Expression.NotEqual(expr, Expression.Constant(null)), 
                                Expression.Not( 
                                    Expression.Call(
                                        typeof(RemotingServices).GetMethod("IsObjectOutOfAppDomain"), 
                                        expr
                                    )
                                )
                            ) 
                        );
                    } 
                    restrictions = restrictions.Merge(remotedRestriction); 
                }
            } 

#endif
            return restrictions;
        } 

        ///  
        /// When overridden in the derived class, performs the binding of the dynamic operation. 
        /// 
        /// The target of the dynamic operation. 
        /// An array of arguments of the dynamic operation.
        /// The  representing the result of the binding.
        public abstract DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args);
 
        /// 
        /// Gets an expression that will cause the binding to be updated. It 
        /// indicates that the expression's binding is no longer valid. 
        /// This is typically used when the "version" of a dynamic object has
        /// changed. 
        /// 
        /// The Type property of the resulting expression; any type is allowed.
        /// The update expression.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] 
        public Expression GetUpdateExpression(Type type) {
            return Expression.Goto(CallSiteBinder.UpdateLabel, type); 
        } 

        ///  
        /// Defers the binding of the operation until later time when the runtime values of all dynamic operation arguments have been computed.
        /// 
        /// The target of the dynamic operation.
        /// An array of arguments of the dynamic operation. 
        /// The  representing the result of the binding.
        public DynamicMetaObject Defer(DynamicMetaObject target, params DynamicMetaObject[] args) { 
            ContractUtils.RequiresNotNull(target, "target"); 

            if (args == null) { 
                return MakeDeferred(target.Restrictions, target);
            } else {
                return MakeDeferred(
                    target.Restrictions.Merge(BindingRestrictions.Combine(args)), 
                    args.AddFirst(target)
                ); 
            } 
        }
 
        /// 
        /// Defers the binding of the operation until later time when the runtime values of all dynamic operation arguments have been computed.
        /// 
        /// An array of arguments of the dynamic operation. 
        /// The  representing the result of the binding.
        public DynamicMetaObject Defer(params DynamicMetaObject[] args) { 
            return MakeDeferred(BindingRestrictions.Combine(args), args); 
        }
 
        private DynamicMetaObject MakeDeferred(BindingRestrictions rs, params DynamicMetaObject[] args) {
            var exprs = DynamicMetaObject.GetExpressions(args);

            Type delegateType = DelegateHelpers.MakeDeferredSiteDelegate(args, ReturnType); 

            // Because we know the arguments match the delegate type (we just created the argument types) 
            // we go directly to DynamicExpression.Make to avoid a bunch of unnecessary argument validation 
            return new DynamicMetaObject(
                DynamicExpression.Make(ReturnType, delegateType, this, new TrueReadOnlyCollection(exprs)), 
                rs
            );
        }
 
        #endregion
 
        // used to detect standard MetaObjectBinders. 
        internal virtual bool IsStandardBinder {
            get { 
                return false;
            }
        }
 
#if !SILVERLIGHT
        private static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject"); 
        private static bool IsComObject(object obj) { 
            // we can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust
            return obj != null && ComObjectType.IsAssignableFrom(obj.GetType()); 
        }
#endif

    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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