DynamicExpression.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 / Core / Microsoft / Scripting / Ast / DynamicExpression.cs / 1305376 / DynamicExpression.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.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Linq.Expressions.Compiler;
using System.Reflection;
using System.Runtime.CompilerServices;
 
#if SILVERLIGHT
using System.Core; 
#endif 

namespace System.Linq.Expressions { 
    /// 
    /// Represents a dynamic operation.
    /// 
#if !SILVERLIGHT 
    [DebuggerTypeProxy(typeof(Expression.DynamicExpressionProxy))]
#endif 
    public class DynamicExpression : Expression, IArgumentProvider { 
        private readonly CallSiteBinder _binder;
        private readonly Type _delegateType; 

        internal DynamicExpression(Type delegateType, CallSiteBinder binder) {
            Debug.Assert(delegateType.GetMethod("Invoke").GetReturnType() == typeof(object) || GetType() != typeof(DynamicExpression));
            _delegateType = delegateType; 
            _binder = binder;
        } 
 
        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, ReadOnlyCollection arguments) {
            if (returnType == typeof(object)) { 
                return new DynamicExpressionN(delegateType, binder, arguments);
            } else {
                return new TypedDynamicExpressionN(returnType, delegateType, binder, arguments);
            } 
        }
 
        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0) { 
            if (returnType == typeof(object)) {
                return new DynamicExpression1(delegateType, binder, arg0); 
            } else {
                return new TypedDynamicExpression1(returnType, delegateType, binder, arg0);
            }
        } 

        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) { 
            if (returnType == typeof(object)) { 
                return new DynamicExpression2(delegateType, binder, arg0, arg1);
            } else { 
                return new TypedDynamicExpression2(returnType, delegateType, binder, arg0, arg1);
            }
        }
 
        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) {
            if (returnType == typeof(object)) { 
                return new DynamicExpression3(delegateType, binder, arg0, arg1, arg2); 
            } else {
                return new TypedDynamicExpression3(returnType, delegateType, binder, arg0, arg1, arg2); 
            }
        }

        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) { 
            if (returnType == typeof(object)) {
                return new DynamicExpression4(delegateType, binder, arg0, arg1, arg2, arg3); 
            } else { 
                return new TypedDynamicExpression4(returnType, delegateType, binder, arg0, arg1, arg2, arg3);
            } 
        }

        /// 
        /// Gets the static type of the expression that this  represents. 
        /// 
        /// The  that represents the static type of the expression. 
        public override Type Type { 
            get { return typeof(object); }
        } 

        /// 
        /// Returns the node type of this Expression. Extension nodes should return
        /// ExpressionType.Extension when overriding this method. 
        /// 
        /// The  of the expression. 
        public sealed override ExpressionType NodeType { 
            get { return ExpressionType.Dynamic; }
        } 

        /// 
        /// Gets the , which determines the runtime behavior of the
        /// dynamic site. 
        /// 
        public CallSiteBinder Binder { 
            get { return _binder; } 
        }
 
        /// 
        /// Gets the type of the delegate used by the .
        /// 
        public Type DelegateType { 
            get { return _delegateType; }
        } 
 
        /// 
        /// Gets the arguments to the dynamic operation. 
        /// 
        public ReadOnlyCollection Arguments {
            get { return GetOrMakeArguments(); }
        } 

        internal virtual ReadOnlyCollection GetOrMakeArguments() { 
            throw ContractUtils.Unreachable; 
        }
 
        /// 
        /// Dispatches to the specific visit method for this node type.
        /// 
        protected internal override Expression Accept(ExpressionVisitor visitor) { 
            return visitor.VisitDynamic(this);
        } 
 
        /// 
        /// Makes a copy of this node replacing the args with the provided values.  The 
        /// number of the args needs to match the number of the current block.
        ///
        /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized
        /// subclass of DynamicExpression which is being used. 
        /// 
        internal virtual DynamicExpression Rewrite(Expression[] args) { 
            throw ContractUtils.Unreachable; 
        }
 
        /// 
        /// Creates a new expression that is like this one, but using the
        /// supplied children. If all of the children are the same, it will
        /// return this expression. 
        /// 
        /// The  property of the result. 
        /// This expression if no children changed, or an expression with the updated children. 
        public DynamicExpression Update(IEnumerable arguments) {
            if (arguments == Arguments) { 
                return this;
            }

            return Expression.MakeDynamic(DelegateType, Binder, arguments); 
        }
 
        #region IArgumentProvider Members 

        Expression IArgumentProvider.GetArgument(int index) { 
            throw ContractUtils.Unreachable;
        }

        int IArgumentProvider.ArgumentCount { 
            get { throw ContractUtils.Unreachable; }
        } 
 
        #endregion
    } 

    #region Specialized Subclasses

    internal class DynamicExpressionN : DynamicExpression, IArgumentProvider { 
        private IList _arguments;       // storage for the original IList or readonly collection.  See IArgumentProvider for more info.
 
        internal DynamicExpressionN(Type delegateType, CallSiteBinder binder, IList arguments) 
            : base(delegateType, binder) {
            _arguments = arguments; 
        }

        Expression IArgumentProvider.GetArgument(int index) {
            return _arguments[index]; 
        }
 
        int IArgumentProvider.ArgumentCount { 
            get {
                return _arguments.Count; 
            }
        }

        internal override ReadOnlyCollection GetOrMakeArguments() { 
            return ReturnReadOnly(ref _arguments);
        } 
 
        internal override DynamicExpression Rewrite(Expression[] args) {
            Debug.Assert(args.Length == ((IArgumentProvider)this).ArgumentCount); 

            return Expression.MakeDynamic(DelegateType, Binder, args);
        }
    } 

    internal class TypedDynamicExpressionN : DynamicExpressionN { 
        private readonly Type _returnType; 

        internal TypedDynamicExpressionN(Type returnType, Type delegateType, CallSiteBinder binder, IList arguments) 
            : base(delegateType, binder, arguments) {
            Debug.Assert(delegateType.GetMethod("Invoke").GetReturnType() == returnType);
            _returnType = returnType;
        } 

        public sealed override Type Type { 
            get { return _returnType; } 
        }
    } 

    internal class DynamicExpression1 : DynamicExpression, IArgumentProvider {
        private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
 
        internal DynamicExpression1(Type delegateType, CallSiteBinder binder, Expression arg0)
            : base(delegateType, binder) { 
            _arg0 = arg0; 
        }
 
        Expression IArgumentProvider.GetArgument(int index) {
            switch (index) {
                case 0: return ReturnObject(_arg0);
                default: throw new InvalidOperationException(); 
            }
        } 
 
        int IArgumentProvider.ArgumentCount {
            get { 
                return 1;
            }
        }
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        } 

        internal override DynamicExpression Rewrite(Expression[] args) { 
            Debug.Assert(args.Length == 1);

            return Expression.MakeDynamic(DelegateType, Binder, args[0]);
        } 
    }
 
    internal sealed class TypedDynamicExpression1 : DynamicExpression1 { 
        private readonly Type _retType;
 
        internal TypedDynamicExpression1(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0)
            : base(delegateType, binder, arg0) {
            _retType = retType;
        } 

        public sealed override Type Type { 
            get { return _retType; } 
        }
    } 

    internal class DynamicExpression2 : DynamicExpression, IArgumentProvider {
        private object _arg0;                   // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
        private readonly Expression _arg1;      // storage for the 2nd argument 

        internal DynamicExpression2(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) 
            : base(delegateType, binder) { 
            _arg0 = arg0;
            _arg1 = arg1; 
        }

        Expression IArgumentProvider.GetArgument(int index) {
            switch (index) { 
                case 0: return ReturnObject(_arg0);
                case 1: return _arg1; 
                default: throw new InvalidOperationException(); 
            }
        } 

        int IArgumentProvider.ArgumentCount {
            get {
                return 2; 
            }
        } 
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        }

        internal override DynamicExpression Rewrite(Expression[] args) {
            Debug.Assert(args.Length == 2); 

            return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1]); 
        } 
    }
 
    internal sealed class TypedDynamicExpression2 : DynamicExpression2 {
        private readonly Type _retType;

        internal TypedDynamicExpression2(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) 
            : base(delegateType, binder, arg0, arg1) {
            _retType = retType; 
        } 

        public sealed override Type Type { 
            get { return _retType; }
        }
    }
 
    internal class DynamicExpression3 : DynamicExpression, IArgumentProvider {
        private object _arg0;                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info. 
        private readonly Expression _arg1, _arg2;   // storage for the 2nd & 3rd arguments 

        internal DynamicExpression3(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) 
            : base(delegateType, binder) {
            _arg0 = arg0;
            _arg1 = arg1;
            _arg2 = arg2; 
        }
 
        Expression IArgumentProvider.GetArgument(int index) { 
            switch (index) {
                case 0: return ReturnObject(_arg0); 
                case 1: return _arg1;
                case 2: return _arg2;
                default: throw new InvalidOperationException();
            } 
        }
 
        int IArgumentProvider.ArgumentCount { 
            get {
                return 3; 
            }
        }

        internal override ReadOnlyCollection GetOrMakeArguments() { 
            return ReturnReadOnly(this, ref _arg0);
        } 
 
        internal override DynamicExpression Rewrite(Expression[] args) {
            Debug.Assert(args.Length == 3); 

            return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1], args[2]);
        }
    } 

    internal sealed class TypedDynamicExpression3 : DynamicExpression3 { 
        private readonly Type _retType; 

        internal TypedDynamicExpression3(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) 
            : base(delegateType, binder, arg0, arg1, arg2) {
            _retType = retType;
        }
 
        public sealed override Type Type {
            get { return _retType; } 
        } 
    }
 
    internal class DynamicExpression4 : DynamicExpression, IArgumentProvider {
        private object _arg0;                               // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
        private readonly Expression _arg1, _arg2, _arg3;    // storage for the 2nd - 4th arguments
 
        internal DynamicExpression4(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3)
            : base(delegateType, binder) { 
            _arg0 = arg0; 
            _arg1 = arg1;
            _arg2 = arg2; 
            _arg3 = arg3;
        }

        Expression IArgumentProvider.GetArgument(int index) { 
            switch (index) {
                case 0: return ReturnObject(_arg0); 
                case 1: return _arg1; 
                case 2: return _arg2;
                case 3: return _arg3; 
                default: throw new InvalidOperationException();
            }
        }
 
        int IArgumentProvider.ArgumentCount {
            get { 
                return 4; 
            }
        } 

        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0);
        } 

        internal override DynamicExpression Rewrite(Expression[] args) { 
            Debug.Assert(args.Length == 4); 

            return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1], args[2], args[3]); 
        }
    }

    internal sealed class TypedDynamicExpression4 : DynamicExpression4 { 
        private readonly Type _retType;
 
        internal TypedDynamicExpression4(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) 
            : base(delegateType, binder, arg0, arg1, arg2, arg3) {
            _retType = retType; 
        }

        public sealed override Type Type {
            get { return _retType; } 
        }
    } 
 
    #endregion
 
    public partial class Expression {

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        /// 
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation. 
        /// The arguments to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// DelegateType,
        /// Binder, and 
        /// Arguments set to the specified values.
        ///  
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, params Expression[] arguments) { 
            return MakeDynamic(delegateType, binder, (IEnumerable)arguments);
        } 

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided .
        ///  
        /// The type of the delegate used by the .
        /// The runtime binder for the dynamic operation. 
        /// The arguments to the dynamic operation. 
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the
        /// DelegateType,
        /// Binder, and
        /// Arguments set to the specified values. 
        /// 
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, IEnumerable arguments) { 
            ContractUtils.RequiresNotNull(delegateType, "delegateType"); 
            ContractUtils.RequiresNotNull(binder, "binder");
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate(); 

            var method = GetValidMethodForDynamic(delegateType);

            var args = arguments.ToReadOnly(); 
            ValidateArgumentTypes(method, ExpressionType.Dynamic, ref args);
 
            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, args); 
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided  and one argument.
        /// 
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation.
        /// The argument to the dynamic operation. 
        ///  
        /// A  that has  equal to
        /// Dynamic and has the 
        /// DelegateType,
        /// Binder, and
        /// Arguments set to the specified values.
        ///  
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0) {
            ContractUtils.RequiresNotNull(delegateType, "delegatType"); 
            ContractUtils.RequiresNotNull(binder, "binder"); 
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
 
            var method = GetValidMethodForDynamic(delegateType);
            var parameters = method.GetParametersCached();

            ValidateArgumentCount(method, ExpressionType.Dynamic, 2, parameters); 
            ValidateDynamicArgument(arg0);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]); 
 
            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0);
        } 

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided  and two arguments.
        ///  
        /// The type of the delegate used by the .
        /// The runtime binder for the dynamic operation. 
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// DelegateType,
        /// Binder, and 
        /// Arguments set to the specified values.
        ///  
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) { 
            ContractUtils.RequiresNotNull(delegateType, "delegatType");
            ContractUtils.RequiresNotNull(binder, "binder"); 
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();

            var method = GetValidMethodForDynamic(delegateType);
            var parameters = method.GetParametersCached(); 

            ValidateArgumentCount(method, ExpressionType.Dynamic, 3, parameters); 
            ValidateDynamicArgument(arg0); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
            ValidateDynamicArgument(arg1); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);

            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1);
        } 

        ///  
        /// Creates a  that represents a dynamic operation bound by the provided  and three arguments. 
        /// 
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation.
        /// The first argument to the dynamic operation.
        /// The second argument to the dynamic operation.
        /// The third argument to the dynamic operation. 
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the 
        /// DelegateType,
        /// Binder, and 
        /// Arguments set to the specified values.
        /// 
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) {
            ContractUtils.RequiresNotNull(delegateType, "delegatType"); 
            ContractUtils.RequiresNotNull(binder, "binder");
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate(); 
 
            var method = GetValidMethodForDynamic(delegateType);
            var parameters = method.GetParametersCached(); 

            ValidateArgumentCount(method, ExpressionType.Dynamic, 4, parameters);
            ValidateDynamicArgument(arg0);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]); 
            ValidateDynamicArgument(arg1);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]); 
            ValidateDynamicArgument(arg2); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg2, parameters[3]);
 
            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1, arg2);
        }

        ///  
        /// Creates a  that represents a dynamic operation bound by the provided  and four arguments.
        ///  
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation.
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation.
        /// The third argument to the dynamic operation.
        /// The fourth argument to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the 
        /// DelegateType, 
        /// Binder, and
        /// Arguments set to the specified values. 
        /// 
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
            ContractUtils.RequiresNotNull(delegateType, "delegatType");
            ContractUtils.RequiresNotNull(binder, "binder"); 
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
 
            var method = GetValidMethodForDynamic(delegateType); 
            var parameters = method.GetParametersCached();
 
            ValidateArgumentCount(method, ExpressionType.Dynamic, 5, parameters);
            ValidateDynamicArgument(arg0);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
            ValidateDynamicArgument(arg1); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);
            ValidateDynamicArgument(arg2); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg2, parameters[3]); 
            ValidateDynamicArgument(arg3);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg3, parameters[4]); 

            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1, arg2, arg3);
        }
 
        private static MethodInfo GetValidMethodForDynamic(Type delegateType) {
            var method = delegateType.GetMethod("Invoke"); 
            var pi = method.GetParametersCached(); 
            if (pi.Length == 0 || pi[0].ParameterType != typeof(CallSite)) throw Error.FirstArgumentMustBeCallSite();
            return method; 
        }

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        /// 
        /// The runtime binder for the dynamic operation. 
        /// The result type of the dynamic expression. 
        /// The arguments to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// Binder and
        /// Arguments set to the specified values. 
        /// 
        ///  
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        ///  
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, params Expression[] arguments) {
            return Dynamic(binder, returnType, (IEnumerable)arguments);
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        ///  
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression. 
        /// The first argument to the dynamic operation.
        /// 
        /// A  that has  equal to
        /// Dynamic and has the 
        /// Binder and
        /// Arguments set to the specified values. 
        ///  
        /// 
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0) {
            ContractUtils.RequiresNotNull(binder, "binder"); 
            ValidateDynamicArgument(arg0);
 
            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo( 
                returnType,
                DelegateHelpers.GetNextTypeInfo( 
                    arg0.Type,
                    DelegateHelpers.NextTypeInfo(typeof(CallSite))
                )
            ); 

            Type delegateType = info.DelegateType; 
            if (delegateType == null) { 
                delegateType = info.MakeDelegateType(returnType, arg0);
            } 

            return DynamicExpression.Make(returnType, delegateType, binder, arg0);
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        ///  
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression. 
        /// The first argument to the dynamic operation.
        /// The second argument to the dynamic operation.
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the
        /// Binder and 
        /// Arguments set to the specified values. 
        /// 
        ///  
        /// The DelegateType property of the
        /// result will be inferred from the types of the arguments and the specified return type.
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1) { 
            ContractUtils.RequiresNotNull(binder, "binder");
            ValidateDynamicArgument(arg0); 
            ValidateDynamicArgument(arg1); 

            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo( 
                returnType,
                DelegateHelpers.GetNextTypeInfo(
                    arg1.Type,
                    DelegateHelpers.GetNextTypeInfo( 
                        arg0.Type,
                        DelegateHelpers.NextTypeInfo(typeof(CallSite)) 
                    ) 
                )
            ); 

            Type delegateType = info.DelegateType;
            if (delegateType == null) {
                delegateType = info.MakeDelegateType(returnType, arg0, arg1); 
            }
 
            return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1); 
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided .
        /// 
        /// The runtime binder for the dynamic operation. 
        /// The result type of the dynamic expression.
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation. 
        /// The third argument to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// Binder and
        /// Arguments set to the specified values. 
        /// 
        ///  
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        ///  
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1, Expression arg2) {
            ContractUtils.RequiresNotNull(binder, "binder");
            ValidateDynamicArgument(arg0);
            ValidateDynamicArgument(arg1); 
            ValidateDynamicArgument(arg2);
 
            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo( 
                returnType,
                DelegateHelpers.GetNextTypeInfo( 
                    arg2.Type,
                    DelegateHelpers.GetNextTypeInfo(
                        arg1.Type,
                        DelegateHelpers.GetNextTypeInfo( 
                            arg0.Type,
                            DelegateHelpers.NextTypeInfo(typeof(CallSite)) 
                        ) 
                    )
                ) 
            );

            Type delegateType = info.DelegateType;
            if (delegateType == null) { 
                delegateType = info.MakeDelegateType(returnType, arg0, arg1, arg2);
            } 
 
            return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1, arg2);
        } 

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided .
        ///  
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression. 
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation.
        /// The third argument to the dynamic operation. 
        /// The fourth argument to the dynamic operation.
        /// 
        /// A  that has  equal to
        /// Dynamic and has the 
        /// Binder and
        /// Arguments set to the specified values. 
        ///  
        /// 
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
            ContractUtils.RequiresNotNull(binder, "binder"); 
            ValidateDynamicArgument(arg0);
            ValidateDynamicArgument(arg1); 
            ValidateDynamicArgument(arg2); 
            ValidateDynamicArgument(arg3);
 
            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo(
                returnType,
                DelegateHelpers.GetNextTypeInfo(
                    arg3.Type, 
                    DelegateHelpers.GetNextTypeInfo(
                        arg2.Type, 
                        DelegateHelpers.GetNextTypeInfo( 
                            arg1.Type,
                            DelegateHelpers.GetNextTypeInfo( 
                                arg0.Type,
                                DelegateHelpers.NextTypeInfo(typeof(CallSite))
                            )
                        ) 
                    )
                ) 
            ); 

            Type delegateType = info.DelegateType; 
            if (delegateType == null) {
                delegateType = info.MakeDelegateType(returnType, arg0, arg1, arg2, arg3);
            }
 
            return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1, arg2, arg3);
        } 
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        /// 
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression.
        /// The arguments to the dynamic operation. 
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the 
        /// Binder and
        /// Arguments set to the specified values. 
        /// 
        /// 
        /// The DelegateType property of the
        /// result will be inferred from the types of the arguments and the specified return type. 
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, IEnumerable arguments) { 
            ContractUtils.RequiresNotNull(arguments, "arguments"); 
            ContractUtils.RequiresNotNull(returnType, "returnType");
 
            var args = arguments.ToReadOnly();
            ContractUtils.RequiresNotEmpty(args, "args");
            return MakeDynamic(binder, returnType, args);
        } 

        private static DynamicExpression MakeDynamic(CallSiteBinder binder, Type returnType, ReadOnlyCollection args) { 
            ContractUtils.RequiresNotNull(binder, "binder"); 

            for (int i = 0; i < args.Count; i++) { 
                Expression arg = args[i];

                ValidateDynamicArgument(arg);
            } 

            Type delegateType = DelegateHelpers.MakeCallSiteDelegate(args, returnType); 
 
            // Since we made a delegate with argument types that exactly match,
            // we can skip delegate and argument validation 

            switch (args.Count) {
                case 1: return DynamicExpression.Make(returnType, delegateType, binder, args[0]);
                case 2: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1]); 
                case 3: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1], args[2]);
                case 4: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1], args[2], args[3]); 
                default: return DynamicExpression.Make(returnType, delegateType, binder, args); 
            }
        } 

        private static void ValidateDynamicArgument(Expression arg) {
            RequiresCanRead(arg, "arguments");
            var type = arg.Type; 
            ContractUtils.RequiresNotNull(type, "type");
            TypeUtils.ValidateType(type); 
            if (type == typeof(void)) throw Error.ArgumentTypeCannotBeVoid(); 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
/* **************************************************************************** 
 *
 * 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.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics;
using System.Dynamic.Utils; 
using System.Linq.Expressions.Compiler;
using System.Reflection;
using System.Runtime.CompilerServices;
 
#if SILVERLIGHT
using System.Core; 
#endif 

namespace System.Linq.Expressions { 
    /// 
    /// Represents a dynamic operation.
    /// 
#if !SILVERLIGHT 
    [DebuggerTypeProxy(typeof(Expression.DynamicExpressionProxy))]
#endif 
    public class DynamicExpression : Expression, IArgumentProvider { 
        private readonly CallSiteBinder _binder;
        private readonly Type _delegateType; 

        internal DynamicExpression(Type delegateType, CallSiteBinder binder) {
            Debug.Assert(delegateType.GetMethod("Invoke").GetReturnType() == typeof(object) || GetType() != typeof(DynamicExpression));
            _delegateType = delegateType; 
            _binder = binder;
        } 
 
        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, ReadOnlyCollection arguments) {
            if (returnType == typeof(object)) { 
                return new DynamicExpressionN(delegateType, binder, arguments);
            } else {
                return new TypedDynamicExpressionN(returnType, delegateType, binder, arguments);
            } 
        }
 
        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0) { 
            if (returnType == typeof(object)) {
                return new DynamicExpression1(delegateType, binder, arg0); 
            } else {
                return new TypedDynamicExpression1(returnType, delegateType, binder, arg0);
            }
        } 

        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) { 
            if (returnType == typeof(object)) { 
                return new DynamicExpression2(delegateType, binder, arg0, arg1);
            } else { 
                return new TypedDynamicExpression2(returnType, delegateType, binder, arg0, arg1);
            }
        }
 
        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) {
            if (returnType == typeof(object)) { 
                return new DynamicExpression3(delegateType, binder, arg0, arg1, arg2); 
            } else {
                return new TypedDynamicExpression3(returnType, delegateType, binder, arg0, arg1, arg2); 
            }
        }

        internal static DynamicExpression Make(Type returnType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) { 
            if (returnType == typeof(object)) {
                return new DynamicExpression4(delegateType, binder, arg0, arg1, arg2, arg3); 
            } else { 
                return new TypedDynamicExpression4(returnType, delegateType, binder, arg0, arg1, arg2, arg3);
            } 
        }

        /// 
        /// Gets the static type of the expression that this  represents. 
        /// 
        /// The  that represents the static type of the expression. 
        public override Type Type { 
            get { return typeof(object); }
        } 

        /// 
        /// Returns the node type of this Expression. Extension nodes should return
        /// ExpressionType.Extension when overriding this method. 
        /// 
        /// The  of the expression. 
        public sealed override ExpressionType NodeType { 
            get { return ExpressionType.Dynamic; }
        } 

        /// 
        /// Gets the , which determines the runtime behavior of the
        /// dynamic site. 
        /// 
        public CallSiteBinder Binder { 
            get { return _binder; } 
        }
 
        /// 
        /// Gets the type of the delegate used by the .
        /// 
        public Type DelegateType { 
            get { return _delegateType; }
        } 
 
        /// 
        /// Gets the arguments to the dynamic operation. 
        /// 
        public ReadOnlyCollection Arguments {
            get { return GetOrMakeArguments(); }
        } 

        internal virtual ReadOnlyCollection GetOrMakeArguments() { 
            throw ContractUtils.Unreachable; 
        }
 
        /// 
        /// Dispatches to the specific visit method for this node type.
        /// 
        protected internal override Expression Accept(ExpressionVisitor visitor) { 
            return visitor.VisitDynamic(this);
        } 
 
        /// 
        /// Makes a copy of this node replacing the args with the provided values.  The 
        /// number of the args needs to match the number of the current block.
        ///
        /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized
        /// subclass of DynamicExpression which is being used. 
        /// 
        internal virtual DynamicExpression Rewrite(Expression[] args) { 
            throw ContractUtils.Unreachable; 
        }
 
        /// 
        /// Creates a new expression that is like this one, but using the
        /// supplied children. If all of the children are the same, it will
        /// return this expression. 
        /// 
        /// The  property of the result. 
        /// This expression if no children changed, or an expression with the updated children. 
        public DynamicExpression Update(IEnumerable arguments) {
            if (arguments == Arguments) { 
                return this;
            }

            return Expression.MakeDynamic(DelegateType, Binder, arguments); 
        }
 
        #region IArgumentProvider Members 

        Expression IArgumentProvider.GetArgument(int index) { 
            throw ContractUtils.Unreachable;
        }

        int IArgumentProvider.ArgumentCount { 
            get { throw ContractUtils.Unreachable; }
        } 
 
        #endregion
    } 

    #region Specialized Subclasses

    internal class DynamicExpressionN : DynamicExpression, IArgumentProvider { 
        private IList _arguments;       // storage for the original IList or readonly collection.  See IArgumentProvider for more info.
 
        internal DynamicExpressionN(Type delegateType, CallSiteBinder binder, IList arguments) 
            : base(delegateType, binder) {
            _arguments = arguments; 
        }

        Expression IArgumentProvider.GetArgument(int index) {
            return _arguments[index]; 
        }
 
        int IArgumentProvider.ArgumentCount { 
            get {
                return _arguments.Count; 
            }
        }

        internal override ReadOnlyCollection GetOrMakeArguments() { 
            return ReturnReadOnly(ref _arguments);
        } 
 
        internal override DynamicExpression Rewrite(Expression[] args) {
            Debug.Assert(args.Length == ((IArgumentProvider)this).ArgumentCount); 

            return Expression.MakeDynamic(DelegateType, Binder, args);
        }
    } 

    internal class TypedDynamicExpressionN : DynamicExpressionN { 
        private readonly Type _returnType; 

        internal TypedDynamicExpressionN(Type returnType, Type delegateType, CallSiteBinder binder, IList arguments) 
            : base(delegateType, binder, arguments) {
            Debug.Assert(delegateType.GetMethod("Invoke").GetReturnType() == returnType);
            _returnType = returnType;
        } 

        public sealed override Type Type { 
            get { return _returnType; } 
        }
    } 

    internal class DynamicExpression1 : DynamicExpression, IArgumentProvider {
        private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
 
        internal DynamicExpression1(Type delegateType, CallSiteBinder binder, Expression arg0)
            : base(delegateType, binder) { 
            _arg0 = arg0; 
        }
 
        Expression IArgumentProvider.GetArgument(int index) {
            switch (index) {
                case 0: return ReturnObject(_arg0);
                default: throw new InvalidOperationException(); 
            }
        } 
 
        int IArgumentProvider.ArgumentCount {
            get { 
                return 1;
            }
        }
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        } 

        internal override DynamicExpression Rewrite(Expression[] args) { 
            Debug.Assert(args.Length == 1);

            return Expression.MakeDynamic(DelegateType, Binder, args[0]);
        } 
    }
 
    internal sealed class TypedDynamicExpression1 : DynamicExpression1 { 
        private readonly Type _retType;
 
        internal TypedDynamicExpression1(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0)
            : base(delegateType, binder, arg0) {
            _retType = retType;
        } 

        public sealed override Type Type { 
            get { return _retType; } 
        }
    } 

    internal class DynamicExpression2 : DynamicExpression, IArgumentProvider {
        private object _arg0;                   // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
        private readonly Expression _arg1;      // storage for the 2nd argument 

        internal DynamicExpression2(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) 
            : base(delegateType, binder) { 
            _arg0 = arg0;
            _arg1 = arg1; 
        }

        Expression IArgumentProvider.GetArgument(int index) {
            switch (index) { 
                case 0: return ReturnObject(_arg0);
                case 1: return _arg1; 
                default: throw new InvalidOperationException(); 
            }
        } 

        int IArgumentProvider.ArgumentCount {
            get {
                return 2; 
            }
        } 
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        }

        internal override DynamicExpression Rewrite(Expression[] args) {
            Debug.Assert(args.Length == 2); 

            return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1]); 
        } 
    }
 
    internal sealed class TypedDynamicExpression2 : DynamicExpression2 {
        private readonly Type _retType;

        internal TypedDynamicExpression2(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) 
            : base(delegateType, binder, arg0, arg1) {
            _retType = retType; 
        } 

        public sealed override Type Type { 
            get { return _retType; }
        }
    }
 
    internal class DynamicExpression3 : DynamicExpression, IArgumentProvider {
        private object _arg0;                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info. 
        private readonly Expression _arg1, _arg2;   // storage for the 2nd & 3rd arguments 

        internal DynamicExpression3(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) 
            : base(delegateType, binder) {
            _arg0 = arg0;
            _arg1 = arg1;
            _arg2 = arg2; 
        }
 
        Expression IArgumentProvider.GetArgument(int index) { 
            switch (index) {
                case 0: return ReturnObject(_arg0); 
                case 1: return _arg1;
                case 2: return _arg2;
                default: throw new InvalidOperationException();
            } 
        }
 
        int IArgumentProvider.ArgumentCount { 
            get {
                return 3; 
            }
        }

        internal override ReadOnlyCollection GetOrMakeArguments() { 
            return ReturnReadOnly(this, ref _arg0);
        } 
 
        internal override DynamicExpression Rewrite(Expression[] args) {
            Debug.Assert(args.Length == 3); 

            return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1], args[2]);
        }
    } 

    internal sealed class TypedDynamicExpression3 : DynamicExpression3 { 
        private readonly Type _retType; 

        internal TypedDynamicExpression3(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) 
            : base(delegateType, binder, arg0, arg1, arg2) {
            _retType = retType;
        }
 
        public sealed override Type Type {
            get { return _retType; } 
        } 
    }
 
    internal class DynamicExpression4 : DynamicExpression, IArgumentProvider {
        private object _arg0;                               // storage for the 1st argument or a readonly collection.  See IArgumentProvider for more info.
        private readonly Expression _arg1, _arg2, _arg3;    // storage for the 2nd - 4th arguments
 
        internal DynamicExpression4(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3)
            : base(delegateType, binder) { 
            _arg0 = arg0; 
            _arg1 = arg1;
            _arg2 = arg2; 
            _arg3 = arg3;
        }

        Expression IArgumentProvider.GetArgument(int index) { 
            switch (index) {
                case 0: return ReturnObject(_arg0); 
                case 1: return _arg1; 
                case 2: return _arg2;
                case 3: return _arg3; 
                default: throw new InvalidOperationException();
            }
        }
 
        int IArgumentProvider.ArgumentCount {
            get { 
                return 4; 
            }
        } 

        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0);
        } 

        internal override DynamicExpression Rewrite(Expression[] args) { 
            Debug.Assert(args.Length == 4); 

            return Expression.MakeDynamic(DelegateType, Binder, args[0], args[1], args[2], args[3]); 
        }
    }

    internal sealed class TypedDynamicExpression4 : DynamicExpression4 { 
        private readonly Type _retType;
 
        internal TypedDynamicExpression4(Type retType, Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) 
            : base(delegateType, binder, arg0, arg1, arg2, arg3) {
            _retType = retType; 
        }

        public sealed override Type Type {
            get { return _retType; } 
        }
    } 
 
    #endregion
 
    public partial class Expression {

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        /// 
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation. 
        /// The arguments to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// DelegateType,
        /// Binder, and 
        /// Arguments set to the specified values.
        ///  
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, params Expression[] arguments) { 
            return MakeDynamic(delegateType, binder, (IEnumerable)arguments);
        } 

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided .
        ///  
        /// The type of the delegate used by the .
        /// The runtime binder for the dynamic operation. 
        /// The arguments to the dynamic operation. 
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the
        /// DelegateType,
        /// Binder, and
        /// Arguments set to the specified values. 
        /// 
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, IEnumerable arguments) { 
            ContractUtils.RequiresNotNull(delegateType, "delegateType"); 
            ContractUtils.RequiresNotNull(binder, "binder");
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate(); 

            var method = GetValidMethodForDynamic(delegateType);

            var args = arguments.ToReadOnly(); 
            ValidateArgumentTypes(method, ExpressionType.Dynamic, ref args);
 
            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, args); 
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided  and one argument.
        /// 
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation.
        /// The argument to the dynamic operation. 
        ///  
        /// A  that has  equal to
        /// Dynamic and has the 
        /// DelegateType,
        /// Binder, and
        /// Arguments set to the specified values.
        ///  
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0) {
            ContractUtils.RequiresNotNull(delegateType, "delegatType"); 
            ContractUtils.RequiresNotNull(binder, "binder"); 
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
 
            var method = GetValidMethodForDynamic(delegateType);
            var parameters = method.GetParametersCached();

            ValidateArgumentCount(method, ExpressionType.Dynamic, 2, parameters); 
            ValidateDynamicArgument(arg0);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]); 
 
            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0);
        } 

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided  and two arguments.
        ///  
        /// The type of the delegate used by the .
        /// The runtime binder for the dynamic operation. 
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// DelegateType,
        /// Binder, and 
        /// Arguments set to the specified values.
        ///  
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1) { 
            ContractUtils.RequiresNotNull(delegateType, "delegatType");
            ContractUtils.RequiresNotNull(binder, "binder"); 
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();

            var method = GetValidMethodForDynamic(delegateType);
            var parameters = method.GetParametersCached(); 

            ValidateArgumentCount(method, ExpressionType.Dynamic, 3, parameters); 
            ValidateDynamicArgument(arg0); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
            ValidateDynamicArgument(arg1); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);

            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1);
        } 

        ///  
        /// Creates a  that represents a dynamic operation bound by the provided  and three arguments. 
        /// 
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation.
        /// The first argument to the dynamic operation.
        /// The second argument to the dynamic operation.
        /// The third argument to the dynamic operation. 
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the 
        /// DelegateType,
        /// Binder, and 
        /// Arguments set to the specified values.
        /// 
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2) {
            ContractUtils.RequiresNotNull(delegateType, "delegatType"); 
            ContractUtils.RequiresNotNull(binder, "binder");
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate(); 
 
            var method = GetValidMethodForDynamic(delegateType);
            var parameters = method.GetParametersCached(); 

            ValidateArgumentCount(method, ExpressionType.Dynamic, 4, parameters);
            ValidateDynamicArgument(arg0);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]); 
            ValidateDynamicArgument(arg1);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]); 
            ValidateDynamicArgument(arg2); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg2, parameters[3]);
 
            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1, arg2);
        }

        ///  
        /// Creates a  that represents a dynamic operation bound by the provided  and four arguments.
        ///  
        /// The type of the delegate used by the . 
        /// The runtime binder for the dynamic operation.
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation.
        /// The third argument to the dynamic operation.
        /// The fourth argument to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the 
        /// DelegateType, 
        /// Binder, and
        /// Arguments set to the specified values. 
        /// 
        public static DynamicExpression MakeDynamic(Type delegateType, CallSiteBinder binder, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
            ContractUtils.RequiresNotNull(delegateType, "delegatType");
            ContractUtils.RequiresNotNull(binder, "binder"); 
            if (!delegateType.IsSubclassOf(typeof(Delegate))) throw Error.TypeMustBeDerivedFromSystemDelegate();
 
            var method = GetValidMethodForDynamic(delegateType); 
            var parameters = method.GetParametersCached();
 
            ValidateArgumentCount(method, ExpressionType.Dynamic, 5, parameters);
            ValidateDynamicArgument(arg0);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg0, parameters[1]);
            ValidateDynamicArgument(arg1); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg1, parameters[2]);
            ValidateDynamicArgument(arg2); 
            ValidateOneArgument(method, ExpressionType.Dynamic, arg2, parameters[3]); 
            ValidateDynamicArgument(arg3);
            ValidateOneArgument(method, ExpressionType.Dynamic, arg3, parameters[4]); 

            return DynamicExpression.Make(method.GetReturnType(), delegateType, binder, arg0, arg1, arg2, arg3);
        }
 
        private static MethodInfo GetValidMethodForDynamic(Type delegateType) {
            var method = delegateType.GetMethod("Invoke"); 
            var pi = method.GetParametersCached(); 
            if (pi.Length == 0 || pi[0].ParameterType != typeof(CallSite)) throw Error.FirstArgumentMustBeCallSite();
            return method; 
        }

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        /// 
        /// The runtime binder for the dynamic operation. 
        /// The result type of the dynamic expression. 
        /// The arguments to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// Binder and
        /// Arguments set to the specified values. 
        /// 
        ///  
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        ///  
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, params Expression[] arguments) {
            return Dynamic(binder, returnType, (IEnumerable)arguments);
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        ///  
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression. 
        /// The first argument to the dynamic operation.
        /// 
        /// A  that has  equal to
        /// Dynamic and has the 
        /// Binder and
        /// Arguments set to the specified values. 
        ///  
        /// 
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0) {
            ContractUtils.RequiresNotNull(binder, "binder"); 
            ValidateDynamicArgument(arg0);
 
            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo( 
                returnType,
                DelegateHelpers.GetNextTypeInfo( 
                    arg0.Type,
                    DelegateHelpers.NextTypeInfo(typeof(CallSite))
                )
            ); 

            Type delegateType = info.DelegateType; 
            if (delegateType == null) { 
                delegateType = info.MakeDelegateType(returnType, arg0);
            } 

            return DynamicExpression.Make(returnType, delegateType, binder, arg0);
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        ///  
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression. 
        /// The first argument to the dynamic operation.
        /// The second argument to the dynamic operation.
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the
        /// Binder and 
        /// Arguments set to the specified values. 
        /// 
        ///  
        /// The DelegateType property of the
        /// result will be inferred from the types of the arguments and the specified return type.
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1) { 
            ContractUtils.RequiresNotNull(binder, "binder");
            ValidateDynamicArgument(arg0); 
            ValidateDynamicArgument(arg1); 

            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo( 
                returnType,
                DelegateHelpers.GetNextTypeInfo(
                    arg1.Type,
                    DelegateHelpers.GetNextTypeInfo( 
                        arg0.Type,
                        DelegateHelpers.NextTypeInfo(typeof(CallSite)) 
                    ) 
                )
            ); 

            Type delegateType = info.DelegateType;
            if (delegateType == null) {
                delegateType = info.MakeDelegateType(returnType, arg0, arg1); 
            }
 
            return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1); 
        }
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided .
        /// 
        /// The runtime binder for the dynamic operation. 
        /// The result type of the dynamic expression.
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation. 
        /// The third argument to the dynamic operation.
        ///  
        /// A  that has  equal to
        /// Dynamic and has the
        /// Binder and
        /// Arguments set to the specified values. 
        /// 
        ///  
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        ///  
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1, Expression arg2) {
            ContractUtils.RequiresNotNull(binder, "binder");
            ValidateDynamicArgument(arg0);
            ValidateDynamicArgument(arg1); 
            ValidateDynamicArgument(arg2);
 
            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo( 
                returnType,
                DelegateHelpers.GetNextTypeInfo( 
                    arg2.Type,
                    DelegateHelpers.GetNextTypeInfo(
                        arg1.Type,
                        DelegateHelpers.GetNextTypeInfo( 
                            arg0.Type,
                            DelegateHelpers.NextTypeInfo(typeof(CallSite)) 
                        ) 
                    )
                ) 
            );

            Type delegateType = info.DelegateType;
            if (delegateType == null) { 
                delegateType = info.MakeDelegateType(returnType, arg0, arg1, arg2);
            } 
 
            return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1, arg2);
        } 

        /// 
        /// Creates a  that represents a dynamic operation bound by the provided .
        ///  
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression. 
        /// The first argument to the dynamic operation. 
        /// The second argument to the dynamic operation.
        /// The third argument to the dynamic operation. 
        /// The fourth argument to the dynamic operation.
        /// 
        /// A  that has  equal to
        /// Dynamic and has the 
        /// Binder and
        /// Arguments set to the specified values. 
        ///  
        /// 
        /// The DelegateType property of the 
        /// result will be inferred from the types of the arguments and the specified return type.
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, Expression arg0, Expression arg1, Expression arg2, Expression arg3) {
            ContractUtils.RequiresNotNull(binder, "binder"); 
            ValidateDynamicArgument(arg0);
            ValidateDynamicArgument(arg1); 
            ValidateDynamicArgument(arg2); 
            ValidateDynamicArgument(arg3);
 
            DelegateHelpers.TypeInfo info = DelegateHelpers.GetNextTypeInfo(
                returnType,
                DelegateHelpers.GetNextTypeInfo(
                    arg3.Type, 
                    DelegateHelpers.GetNextTypeInfo(
                        arg2.Type, 
                        DelegateHelpers.GetNextTypeInfo( 
                            arg1.Type,
                            DelegateHelpers.GetNextTypeInfo( 
                                arg0.Type,
                                DelegateHelpers.NextTypeInfo(typeof(CallSite))
                            )
                        ) 
                    )
                ) 
            ); 

            Type delegateType = info.DelegateType; 
            if (delegateType == null) {
                delegateType = info.MakeDelegateType(returnType, arg0, arg1, arg2, arg3);
            }
 
            return DynamicExpression.Make(returnType, delegateType, binder, arg0, arg1, arg2, arg3);
        } 
 
        /// 
        /// Creates a  that represents a dynamic operation bound by the provided . 
        /// 
        /// The runtime binder for the dynamic operation.
        /// The result type of the dynamic expression.
        /// The arguments to the dynamic operation. 
        /// 
        /// A  that has  equal to 
        /// Dynamic and has the 
        /// Binder and
        /// Arguments set to the specified values. 
        /// 
        /// 
        /// The DelegateType property of the
        /// result will be inferred from the types of the arguments and the specified return type. 
        /// 
        public static DynamicExpression Dynamic(CallSiteBinder binder, Type returnType, IEnumerable arguments) { 
            ContractUtils.RequiresNotNull(arguments, "arguments"); 
            ContractUtils.RequiresNotNull(returnType, "returnType");
 
            var args = arguments.ToReadOnly();
            ContractUtils.RequiresNotEmpty(args, "args");
            return MakeDynamic(binder, returnType, args);
        } 

        private static DynamicExpression MakeDynamic(CallSiteBinder binder, Type returnType, ReadOnlyCollection args) { 
            ContractUtils.RequiresNotNull(binder, "binder"); 

            for (int i = 0; i < args.Count; i++) { 
                Expression arg = args[i];

                ValidateDynamicArgument(arg);
            } 

            Type delegateType = DelegateHelpers.MakeCallSiteDelegate(args, returnType); 
 
            // Since we made a delegate with argument types that exactly match,
            // we can skip delegate and argument validation 

            switch (args.Count) {
                case 1: return DynamicExpression.Make(returnType, delegateType, binder, args[0]);
                case 2: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1]); 
                case 3: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1], args[2]);
                case 4: return DynamicExpression.Make(returnType, delegateType, binder, args[0], args[1], args[2], args[3]); 
                default: return DynamicExpression.Make(returnType, delegateType, binder, args); 
            }
        } 

        private static void ValidateDynamicArgument(Expression arg) {
            RequiresCanRead(arg, "arguments");
            var type = arg.Type; 
            ContractUtils.RequiresNotNull(type, "type");
            TypeUtils.ValidateType(type); 
            if (type == typeof(void)) throw Error.ArgumentTypeCannotBeVoid(); 
        }
    } 
}

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