MethodCallExpression.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 / Ast / MethodCallExpression.cs / 1305376 / MethodCallExpression.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.Reflection;
using System.Runtime.CompilerServices;

#if SILVERLIGHT 
using System.Core;
#endif 
 
namespace System.Linq.Expressions {
    ///  
    /// Represents a call to either static or an instance method.
    /// 
#if !SILVERLIGHT
    [DebuggerTypeProxy(typeof(Expression.MethodCallExpressionProxy))] 
#endif
    public class MethodCallExpression : Expression, IArgumentProvider { 
        private readonly MethodInfo _method; 

        internal MethodCallExpression(MethodInfo method) { 

            _method = method;
        }
 
        internal virtual Expression GetInstance() {
            return null; 
        } 

        ///  
        /// Returns the node type of this . (Inherited from .)
        /// 
        /// The  that represents this expression.
        public sealed override ExpressionType NodeType { 
            get { return ExpressionType.Call; }
        } 
 
        /// 
        /// Gets the static type of the expression that this  represents. (Inherited from .) 
        /// 
        /// The  that represents the static type of the expression.
        public sealed override Type Type {
            get { return _method.ReturnType; } 
        }
 
        ///  
        /// Gets the  for the method to be called.
        ///  
        public MethodInfo Method {
            get { return _method; }
        }
 
        /// 
        /// Gets the  that represents the instance 
        /// for instance method calls or null for static method cals. 
        /// 
        public Expression Object { 
            get { return GetInstance(); }
        }

        ///  
        /// Gets a collection of expressions that represent arguments to the method call.
        ///  
        public ReadOnlyCollection Arguments { 
            get { return GetOrMakeArguments(); }
        } 

        /// 
        /// 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. 
        /// The  property of the result.
        /// This expression if no children changed, or an expression with the updated children. 
        public MethodCallExpression Update(Expression @object, IEnumerable arguments) {
            if (@object == Object && arguments == Arguments) {
                return this;
            } 
            return Expression.Call(@object, Method, arguments);
        } 
 
        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.VisitMethodCall(this); 
        }
 
        /// 
        /// Returns a new MethodCallExpression replacing the existing instance/args with the
        /// newly provided instance and args.    Arguments can be null to use the existing
        /// arguments. 
        ///
        /// This helper is provided to allow re-writing of nodes to not depend on the specific optimized 
        /// subclass of MethodCallExpression which is being used. 
        /// 
        internal virtual MethodCallExpression Rewrite(Expression instance, IList args) { 
            throw ContractUtils.Unreachable;
        }

        #region IArgumentProvider Members 

        Expression IArgumentProvider.GetArgument(int index) { 
            throw ContractUtils.Unreachable; 
        }
 
        int IArgumentProvider.ArgumentCount {
            get { throw ContractUtils.Unreachable; }
        }
 
        #endregion
    } 
 
    #region Specialized Subclasses
 
    internal class MethodCallExpressionN : MethodCallExpression, IArgumentProvider {
        private IList _arguments;

        public MethodCallExpressionN(MethodInfo method, IList args) 
            : base(method) {
            _arguments = args; 
        } 

        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 MethodCallExpression Rewrite(Expression instance, IList args) {
            Debug.Assert(instance == null); 
            Debug.Assert(args == null || args.Count == _arguments.Count); 

            return Expression.Call(Method, args ?? _arguments); 
        }
    }

    internal class InstanceMethodCallExpressionN : MethodCallExpression, IArgumentProvider { 
        private IList _arguments;
        private readonly Expression _instance; 
 
        public InstanceMethodCallExpressionN(MethodInfo method, Expression instance, IList args)
            : base(method) { 
            _instance = instance;
            _arguments = args;
        }
 
        Expression IArgumentProvider.GetArgument(int index) {
            return _arguments[index]; 
        } 

        int IArgumentProvider.ArgumentCount { 
            get {
                return _arguments.Count;
            }
        } 

        internal override Expression GetInstance() { 
            return _instance; 
        }
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(ref _arguments);
        }
 
        internal override MethodCallExpression Rewrite(Expression instance, IList args) {
            Debug.Assert(instance != null); 
            Debug.Assert(args == null || args.Count == _arguments.Count); 

            return Expression.Call(instance, Method, args ?? _arguments); 
        }
    }

    internal class MethodCallExpression1 : MethodCallExpression, IArgumentProvider { 
        private object _arg0;       // storage for the 1st argument or a readonly collection.  See IArgumentProvider
 
        public MethodCallExpression1(MethodInfo method, Expression arg0) 
            : base(method) {
            _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 MethodCallExpression Rewrite(Expression instance, IList args) {
            Debug.Assert(instance == null);
            Debug.Assert(args == null || args.Count == 1); 

            if (args != null) { 
                return Expression.Call(Method, args[0]); 
            }
 
            return Expression.Call(Method, ReturnObject(_arg0));
        }
    }
 
    internal class MethodCallExpression2 : MethodCallExpression, IArgumentProvider {
        private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider 
        private readonly Expression _arg1;  // storage for the 2nd arg 

        public MethodCallExpression2(MethodInfo method, Expression arg0, Expression arg1) 
            : base(method) {
            _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 MethodCallExpression Rewrite(Expression instance, IList args) { 
            Debug.Assert(instance == null); 
            Debug.Assert(args == null || args.Count == 2);
 
            if (args != null) {
                return Expression.Call(Method, args[0], args[1]);
            }
            return Expression.Call(Method, ReturnObject(_arg0), _arg1); 
        }
    } 
 
    internal class MethodCallExpression3 : MethodCallExpression, IArgumentProvider {
        private object _arg0;           // storage for the 1st argument or a readonly collection.  See IArgumentProvider 
        private readonly Expression _arg1, _arg2; // storage for the 2nd - 3rd args.

        public MethodCallExpression3(MethodInfo method, Expression arg0, Expression arg1, Expression arg2)
            : base(method) { 
            _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 MethodCallExpression Rewrite(Expression instance, IList args) {
            Debug.Assert(instance == null);
            Debug.Assert(args == null || args.Count == 3); 

            if (args != null) { 
                return Expression.Call(Method, args[0], args[1], args[2]); 
            }
            return Expression.Call(Method, ReturnObject(_arg0), _arg1, _arg2); 
        }
    }

    internal class MethodCallExpression4 : MethodCallExpression, IArgumentProvider { 
        private object _arg0;               // storage for the 1st argument or a readonly collection.  See IArgumentProvider
        private readonly Expression _arg1, _arg2, _arg3;  // storage for the 2nd - 4th args. 
 
        public MethodCallExpression4(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3)
            : base(method) { 
            _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 MethodCallExpression Rewrite(Expression instance, IList args) { 
            Debug.Assert(instance == null);
            Debug.Assert(args == null || args.Count == 4);

            if (args != null) { 
                return Expression.Call(Method, args[0], args[1], args[2], args[3]);
            } 
            return Expression.Call(Method, ReturnObject(_arg0), _arg1, _arg2, _arg3); 
        }
    } 

    internal class MethodCallExpression5 : MethodCallExpression, IArgumentProvider {
        private object _arg0;           // storage for the 1st argument or a readonly collection.  See IArgumentProvider
        private readonly Expression _arg1, _arg2, _arg3, _arg4;   // storage for the 2nd - 5th args. 

        public MethodCallExpression5(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) 
            : base(method) { 
            _arg0 = arg0;
            _arg1 = arg1; 
            _arg2 = arg2;
            _arg3 = arg3;
            _arg4 = arg4;
        } 

        Expression IArgumentProvider.GetArgument(int index) { 
            switch (index) { 
                case 0: return ReturnObject(_arg0);
                case 1: return _arg1; 
                case 2: return _arg2;
                case 3: return _arg3;
                case 4: return _arg4;
                default: throw new InvalidOperationException(); 
            }
        } 
 
        int IArgumentProvider.ArgumentCount {
            get { 
                return 5;
            }
        }
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        } 

        internal override MethodCallExpression Rewrite(Expression instance, IList args) { 
            Debug.Assert(instance == null);
            Debug.Assert(args == null || args.Count == 5);

            if (args != null) { 
                return Expression.Call(Method, args[0], args[1], args[2], args[3], args[4]);
            } 
 
            return Expression.Call(Method, ReturnObject(_arg0), _arg1, _arg2, _arg3, _arg4);
        } 
    }

    internal class InstanceMethodCallExpression2 : MethodCallExpression, IArgumentProvider {
        private readonly Expression _instance; 
        private object _arg0;                // storage for the 1st argument or a readonly collection.  See IArgumentProvider
        private readonly Expression _arg1;   // storage for the 2nd argument 
 
        public InstanceMethodCallExpression2(MethodInfo method, Expression instance, Expression arg0, Expression arg1)
            : base(method) { 
            Debug.Assert(instance != null);

            _instance = instance;
            _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 Expression GetInstance() { 
            return _instance;
        } 
 
        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        }

        internal override MethodCallExpression Rewrite(Expression instance, IList args) {
            Debug.Assert(instance != null); 
            Debug.Assert(args == null || args.Count == 2);
 
            if (args != null) { 
                return Expression.Call(instance, Method, args[0], args[1]);
            } 
            return Expression.Call(instance, Method, ReturnObject(_arg0), _arg1);
        }
    }
 
    internal class InstanceMethodCallExpression3 : MethodCallExpression, IArgumentProvider {
        private readonly Expression _instance; 
        private object _arg0;                       // storage for the 1st argument or a readonly collection.  See IArgumentProvider 
        private readonly Expression _arg1, _arg2;   // storage for the 2nd - 3rd argument
 
        public InstanceMethodCallExpression3(MethodInfo method, Expression instance, Expression arg0, Expression arg1, Expression arg2)
            : base(method) {
            Debug.Assert(instance != null);
 
            _instance = instance;
            _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 Expression GetInstance() {
            return _instance; 
        }

        internal override ReadOnlyCollection GetOrMakeArguments() {
            return ReturnReadOnly(this, ref _arg0); 
        }
 
        internal override MethodCallExpression Rewrite(Expression instance, IList args) { 
            Debug.Assert(instance != null);
            Debug.Assert(args == null || args.Count == 3); 

            if (args != null) {
                return Expression.Call(instance, Method, args[0], args[1], args[2]);
            } 
            return Expression.Call(instance, Method, ReturnObject(_arg0), _arg1, _arg2);
        } 
    } 

    #endregion 

    public partial class Expression {

        #region Call 

        ///Creates a  that represents a call to a static method that takes one argument. 
        ///A  that has the  property equal to  and the  and  properties set to the specified values. 
        ///A  to set the  property equal to.
        ///The  that represents the first argument. 
        ///
        /// is null.
        public static MethodCallExpression Call(MethodInfo method, Expression arg0) {
            ContractUtils.RequiresNotNull(method, "method"); 
            ContractUtils.RequiresNotNull(arg0, "arg0");
 
            ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method); 

            ValidateArgumentCount(method, ExpressionType.Call, 1, pis); 

            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);

            return new MethodCallExpression1(method, arg0); 
        }
 
        ///Creates a  that represents a call to a static method that takes two arguments. 
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        ///A  to set the  property equal to. 
        ///The  that represents the first argument.
        ///The  that represents the second argument.
        ///
        /// is null. 
        public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1) {
            ContractUtils.RequiresNotNull(method, "method"); 
            ContractUtils.RequiresNotNull(arg0, "arg0"); 
            ContractUtils.RequiresNotNull(arg1, "arg1");
 
            ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);

            ValidateArgumentCount(method, ExpressionType.Call, 2, pis);
 
            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
            arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]); 
 
            return new MethodCallExpression2(method, arg0, arg1);
        } 

        ///Creates a  that represents a call to a static method that takes three arguments.
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        ///A  to set the  property equal to. 
        ///The  that represents the first argument.
        ///The  that represents the second argument. 
        ///The  that represents the third argument. 
        ///
        /// is null. 
        public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2) {
            ContractUtils.RequiresNotNull(method, "method");
            ContractUtils.RequiresNotNull(arg0, "arg0");
            ContractUtils.RequiresNotNull(arg1, "arg1"); 
            ContractUtils.RequiresNotNull(arg2, "arg2");
 
            ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method); 

            ValidateArgumentCount(method, ExpressionType.Call, 3, pis); 

            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
            arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
            arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]); 

            return new MethodCallExpression3(method, arg0, arg1, arg2); 
        } 

        ///Creates a  that represents a call to a static method that takes four arguments. 
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        ///A  to set the  property equal to.
        ///The  that represents the first argument.
        ///The  that represents the second argument. 
        ///The  that represents the third argument.
        ///The  that represents the fourth argument. 
        /// 
        /// is null.
        public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3) { 
            ContractUtils.RequiresNotNull(method, "method");
            ContractUtils.RequiresNotNull(arg0, "arg0");
            ContractUtils.RequiresNotNull(arg1, "arg1");
            ContractUtils.RequiresNotNull(arg2, "arg2"); 
            ContractUtils.RequiresNotNull(arg3, "arg3");
 
            ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method); 

            ValidateArgumentCount(method, ExpressionType.Call, 4, pis); 

            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
            arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);
            arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]); 
            arg3 = ValidateOneArgument(method, ExpressionType.Call, arg3, pis[3]);
 
            return new MethodCallExpression4(method, arg0, arg1, arg2, arg3); 
        }
 
        ///Creates a  that represents a call to a static method that takes five arguments.
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        ///A  to set the  property equal to.
        ///The  that represents the first argument. 
        ///The  that represents the second argument.
        ///The  that represents the third argument. 
        ///The  that represents the fourth argument. 
        ///The  that represents the fifth argument.
        /// 
        /// is null.
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        public static MethodCallExpression Call(MethodInfo method, Expression arg0, Expression arg1, Expression arg2, Expression arg3, Expression arg4) {
            ContractUtils.RequiresNotNull(method, "method"); 
            ContractUtils.RequiresNotNull(arg0, "arg0");
            ContractUtils.RequiresNotNull(arg1, "arg1"); 
            ContractUtils.RequiresNotNull(arg2, "arg2"); 
            ContractUtils.RequiresNotNull(arg3, "arg3");
            ContractUtils.RequiresNotNull(arg4, "arg4"); 

            ParameterInfo[] pis = ValidateMethodAndGetParameters(null, method);

            ValidateArgumentCount(method, ExpressionType.Call, 5, pis); 

            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]); 
            arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]); 
            arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]);
            arg3 = ValidateOneArgument(method, ExpressionType.Call, arg3, pis[3]); 
            arg4 = ValidateOneArgument(method, ExpressionType.Call, arg4, pis[4]);

            return new MethodCallExpression5(method, arg0, arg1, arg2, arg3, arg4);
        } 

        ///  
        /// Creates a  that represents a call to a static (Shared in Visual Basic) method. 
        /// 
        /// The  that represents the target method. 
        /// The array of one or more of  that represents the call arguments.
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        public static MethodCallExpression Call(MethodInfo method, params Expression[] arguments) {
            return Call(null, method, arguments); 
        }
 
        ///  
        /// Creates a  that represents a call to a static (Shared in Visual Basic) method.
        ///  
        /// The  that represents the target method.
        /// A collection of  that represents the call arguments.
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        public static MethodCallExpression Call(MethodInfo method, IEnumerable arguments) { 
            return Call(null, method, arguments);
        } 
 
        /// 
        /// Creates a  that represents a call to a method that takes no arguments. 
        /// 
        /// An  that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).
        /// The  that represents the target method.
        ///A  that has the  property equal to  and the  and  properties set to the specified values. 
        public static MethodCallExpression Call(Expression instance, MethodInfo method) {
            return Call(instance, method, EmptyReadOnlyCollection.Instance); 
        } 

        ///  
        /// Creates a  that represents a method call.
        /// 
        /// An  that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).
        /// The  that represents the target method. 
        /// An array of one or more of  that represents the call arguments.
        ///A  that has the  property equal to  and the  and  properties set to the specified values. 
        public static MethodCallExpression Call(Expression instance, MethodInfo method, params Expression[] arguments) { 
            return Call(instance, method, (IEnumerable)arguments);
        } 

        /// 
        /// Creates a  that represents a call to a method that takes two arguments.
        ///  
        /// An  that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).
        /// The  that represents the target method. 
        /// The  that represents the first argument. 
        /// The  that represents the second argument.
        ///A  that has the  property equal to  and the  and  properties set to the specified values. 
        public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1) {
            ContractUtils.RequiresNotNull(method, "method");
            ContractUtils.RequiresNotNull(arg0, "arg0");
            ContractUtils.RequiresNotNull(arg1, "arg1"); 

            ParameterInfo[] pis = ValidateMethodAndGetParameters(instance, method); 
 
            ValidateArgumentCount(method, ExpressionType.Call, 2, pis);
 
            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
            arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]);

            if (instance != null) { 
                return new InstanceMethodCallExpression2(method, instance, arg0, arg1);
            } 
 
            return new MethodCallExpression2(method, arg0, arg1);
        } 

        /// 
        /// Creates a  that represents a call to a method that takes three arguments.
        ///  
        /// An  that specifies the instance for an instance call. (pass null for a static (Shared in Visual Basic) method).
        /// The  that represents the target method. 
        /// The  that represents the first argument. 
        /// The  that represents the second argument.
        /// The  that represents the third argument. 
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        public static MethodCallExpression Call(Expression instance, MethodInfo method, Expression arg0, Expression arg1, Expression arg2) {
            ContractUtils.RequiresNotNull(method, "method");
            ContractUtils.RequiresNotNull(arg0, "arg0"); 
            ContractUtils.RequiresNotNull(arg1, "arg1");
            ContractUtils.RequiresNotNull(arg2, "arg2"); 
 
            ParameterInfo[] pis = ValidateMethodAndGetParameters(instance, method);
 
            ValidateArgumentCount(method, ExpressionType.Call, 3, pis);

            arg0 = ValidateOneArgument(method, ExpressionType.Call, arg0, pis[0]);
            arg1 = ValidateOneArgument(method, ExpressionType.Call, arg1, pis[1]); 
            arg2 = ValidateOneArgument(method, ExpressionType.Call, arg2, pis[2]);
 
            if (instance != null) { 
                return new InstanceMethodCallExpression3(method, instance, arg0, arg1, arg2);
            } 
            return new MethodCallExpression3(method, arg0, arg1, arg2);
        }

        ///Creates a  that represents a call to an instance method by calling the appropriate factory method. 
        ///A  that has the  property equal to , the  property equal to ,  set to the  that represents the specified instance method, and  set to the specified arguments.
        ///An  whose  property value will be searched for a specific method. 
        ///The name of the method. 
        ///
        ///An array of  objects that specify the type parameters of the generic method. 
        ///This argument should be null when  specifies a non-generic method.
        ///
        ///An array of  objects that represents the arguments to the method.
        /// 
        /// or  is null.
        ///No method whose name is , whose type parameters match , and whose parameter types match  is found in .Type or its base types.-or-More than one method whose name is , whose type parameters match , and whose parameter types match  is found in .Type or its base types. 
        public static MethodCallExpression Call(Expression instance, string methodName, Type[] typeArguments, params Expression[] arguments) { 
            ContractUtils.RequiresNotNull(instance, "instance");
            ContractUtils.RequiresNotNull(methodName, "methodName"); 
            if (arguments == null) {
                arguments = new Expression[0];
            }
 
            BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
            return Expression.Call(instance, FindMethod(instance.Type, methodName, typeArguments, arguments, flags), arguments); 
        } 

        ///Creates a  that represents a call to a static (Shared in Visual Basic) method by calling the appropriate factory method. 
        ///A  that has the  property equal to , the  property set to the  that represents the specified static (Shared in Visual Basic) method, and the  property set to the specified arguments.
        ///The  that specifies the type that contains the specified static (Shared in Visual Basic) method.
        ///The name of the method.
        /// 
        ///An array of  objects that specify the type parameters of the generic method.
        ///This argument should be null when  specifies a non-generic method. 
        /// 
        ///An array of  objects that represent the arguments to the method.
        /// 
        /// or  is null.
        ///No method whose name is , whose type parameters match , and whose parameter types match  is found in  or its base types.-or-More than one method whose name is , whose type parameters match , and whose parameter types match  is found in  or its base types.
        public static MethodCallExpression Call(Type type, string methodName, Type[] typeArguments, params Expression[] arguments) {
            ContractUtils.RequiresNotNull(type, "type"); 
            ContractUtils.RequiresNotNull(methodName, "methodName");
 
            if (arguments == null) arguments = new Expression[] { }; 
            BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;
            return Expression.Call(null, FindMethod(type, methodName, typeArguments, arguments, flags), arguments); 
        }

        ///Creates a  that represents a method call.
        ///A  that has the  property equal to  and the , , and  properties set to the specified values. 
        ///An  to set the  property equal to (pass null for a static (Shared in Visual Basic) method).
        ///A  to set the  property equal to. 
        ///An  that contains  objects to use to populate the  collection. 
        ///
        /// is null.-or- is null and  represents an instance method. 
        ///
        ///.Type is not assignable to the declaring type of the method represented by .-or-The number of elements in  does not equal the number of parameters for the method represented by .-or-One or more of the elements of  is not assignable to the corresponding parameter for the method represented by .
        public static MethodCallExpression Call(Expression instance, MethodInfo method, IEnumerable arguments) {
            ContractUtils.RequiresNotNull(method, "method"); 

            ReadOnlyCollection argList = arguments.ToReadOnly(); 
 
            ValidateMethodInfo(method);
            ValidateStaticOrInstanceMethod(instance, method); 
            ValidateArgumentTypes(method, ExpressionType.Call, ref argList);

            if (instance == null) {
                return new MethodCallExpressionN(method, argList); 
            } else {
                return new InstanceMethodCallExpressionN(method, instance, argList); 
            } 
        }
 
        private static ParameterInfo[] ValidateMethodAndGetParameters(Expression instance, MethodInfo method) {
            ValidateMethodInfo(method);
            ValidateStaticOrInstanceMethod(instance, method);
 
            return GetParametersForValidation(method, ExpressionType.Call);
        } 
 
        private static void ValidateStaticOrInstanceMethod(Expression instance, MethodInfo method) {
            if (method.IsStatic) { 
                if (instance != null) throw new ArgumentException(Strings.OnlyStaticMethodsHaveNullInstance, "instance");
            } else {
                if (instance == null) throw new ArgumentException(Strings.OnlyStaticMethodsHaveNullInstance, "method");
                RequiresCanRead(instance, "instance"); 
                ValidateCallInstanceType(instance.Type, method);
            } 
        } 

        private static void ValidateCallInstanceType(Type instanceType, MethodInfo method) { 
            if (!TypeUtils.IsValidInstanceType(method, instanceType)) {
                throw Error.InstanceAndMethodTypeMismatch(method, method.DeclaringType, instanceType);
            }
        } 

        private static void ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection arguments) { 
            Debug.Assert(nodeKind == ExpressionType.Invoke || nodeKind == ExpressionType.Call || nodeKind == ExpressionType.Dynamic || nodeKind == ExpressionType.New); 

            ParameterInfo[] pis = GetParametersForValidation(method, nodeKind); 

            ValidateArgumentCount(method, nodeKind, arguments.Count, pis);

            Expression[] newArgs = null; 
            for (int i = 0, n = pis.Length; i < n; i++) {
                Expression arg = arguments[i]; 
                ParameterInfo pi = pis[i]; 
                arg = ValidateOneArgument(method, nodeKind, arg, pi);
 
                if (newArgs == null && arg != arguments[i]) {
                    newArgs = new Expression[arguments.Count];
                    for (int j = 0; j < i; j++) {
                        newArgs[j] = arguments[j]; 
                    }
                } 
                if (newArgs != null) { 
                    newArgs[i] = arg;
                } 
            }
            if (newArgs != null) {
                arguments = new TrueReadOnlyCollection(newArgs);
            } 
        }
 
        private static ParameterInfo[] GetParametersForValidation(MethodBase method, ExpressionType nodeKind) { 
            ParameterInfo[] pis = method.GetParametersCached();
 
            if (nodeKind == ExpressionType.Dynamic) {
                pis = pis.RemoveFirst(); // ignore CallSite argument
            }
            return pis; 
        }
 
        private static void ValidateArgumentCount(MethodBase method, ExpressionType nodeKind, int count, ParameterInfo[] pis) { 
            if (pis.Length != count) {
                // Throw the right error for the node we were given 
                switch (nodeKind) {
                    case ExpressionType.New:
                        throw Error.IncorrectNumberOfConstructorArguments();
                    case ExpressionType.Invoke: 
                        throw Error.IncorrectNumberOfLambdaArguments();
                    case ExpressionType.Dynamic: 
                    case ExpressionType.Call: 
                        throw Error.IncorrectNumberOfMethodCallArguments(method);
                    default: 
                        throw ContractUtils.Unreachable;
                }
            }
        } 

        private static Expression ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi) { 
            RequiresCanRead(arg, "arguments"); 
            Type pType = pi.ParameterType;
            if (pType.IsByRef) { 
                pType = pType.GetElementType();
            }
            TypeUtils.ValidateType(pType);
            if (!TypeUtils.AreReferenceAssignable(pType, arg.Type)) { 
                if (TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType())) {
                    arg = Expression.Quote(arg); 
                } else { 
                    // Throw the right error for the node we were given
                    switch (nodeKind) { 
                        case ExpressionType.New:
                            throw Error.ExpressionTypeDoesNotMatchConstructorParameter(arg.Type, pType);
                        case ExpressionType.Invoke:
                            throw Error.ExpressionTypeDoesNotMatchParameter(arg.Type, pType); 
                        case ExpressionType.Dynamic:
                        case ExpressionType.Call: 
                            throw Error.ExpressionTypeDoesNotMatchMethodParameter(arg.Type, pType, method); 
                        default:
                            throw ContractUtils.Unreachable; 
                    }
                }
            }
            return arg; 
        }
 
        private static MethodInfo FindMethod(Type type, string methodName, Type[] typeArgs, Expression[] args, BindingFlags flags) { 
            MemberInfo[] members = type.FindMembers(MemberTypes.Method, flags, Type.FilterNameIgnoreCase, methodName);
            if (members == null || members.Length == 0) 
                throw Error.MethodDoesNotExistOnType(methodName, type);

            MethodInfo method;
 
            var methodInfos = members.Map(t => (MethodInfo)t);
            int count = FindBestMethod(methodInfos, typeArgs, args, out method); 
 
            if (count == 0) {
                if (typeArgs != null && typeArgs.Length > 0) { 
                    throw Error.GenericMethodWithArgsDoesNotExistOnType(methodName, type);
                } else {
                    throw Error.MethodWithArgsDoesNotExistOnType(methodName, type);
                } 
            }
            if (count > 1) 
                throw Error.MethodWithMoreThanOneMatch(methodName, type); 
            return method;
        } 

        private static int FindBestMethod(IEnumerable methods, Type[] typeArgs, Expression[] args, out MethodInfo method) {
            int count = 0;
            method = null; 
            foreach (MethodInfo mi in methods) {
                MethodInfo moo = ApplyTypeArgs(mi, typeArgs); 
                if (moo != null && IsCompatible(moo, args)) { 
                    // favor public over non-public methods
                    if (method == null || (!method.IsPublic && moo.IsPublic)) { 
                        method = moo;
                        count = 1;
                    }
                        // only count it as additional method if they both public or both non-public 
                    else if (method.IsPublic == moo.IsPublic) {
                        count++; 
                    } 
                }
            } 
            return count;
        }

        private static bool IsCompatible(MethodBase m, Expression[] args) { 
            ParameterInfo[] parms = m.GetParametersCached();
            if (parms.Length != args.Length) 
                return false; 
            for (int i = 0; i < args.Length; i++) {
                Expression arg = args[i]; 
                ContractUtils.RequiresNotNull(arg, "argument");
                Type argType = arg.Type;
                Type pType = parms[i].ParameterType;
                if (pType.IsByRef) { 
                    pType = pType.GetElementType();
                } 
                if (!TypeUtils.AreReferenceAssignable(pType, argType) && 
                    !(TypeUtils.IsSameOrSubclass(typeof(LambdaExpression), pType) && pType.IsAssignableFrom(arg.GetType()))) {
                    return false; 
                }
            }
            return true;
        } 

        private static MethodInfo ApplyTypeArgs(MethodInfo m, Type[] typeArgs) { 
            if (typeArgs == null || typeArgs.Length == 0) { 
                if (!m.IsGenericMethodDefinition)
                    return m; 
            } else {
                if (m.IsGenericMethodDefinition && m.GetGenericArguments().Length == typeArgs.Length)
                    return m.MakeGenericMethod(typeArgs);
            } 
            return null;
        } 
 

        #endregion 

        #region ArrayIndex

        ///Creates a  that represents applying an array index operator to a multi-dimensional array. 
        ///A  that has the  property equal to  and the  and  properties set to the specified values.
        ///An array of  instances - indexes for the array index operation. 
        ///An array that contains  objects to use to populate the  collection. 
        public static MethodCallExpression ArrayIndex(Expression array, params Expression[] indexes) {
            return ArrayIndex(array, (IEnumerable)indexes); 
        }

        ///Creates a  that represents applying an array index operator to an array of rank more than one.
        ///A  that has the  property equal to  and the  and  properties set to the specified values. 
        ///An  to set the  property equal to.
        ///An  that contains  objects to use to populate the  collection. 
        /// 
        /// or  is null.
        /// 
        ///.Type does not represent an array type.-or-The rank of .Type does not match the number of elements in .-or-The  property of one or more elements of  does not represent the  type.
        public static MethodCallExpression ArrayIndex(Expression array, IEnumerable indexes) {
            RequiresCanRead(array, "array");
            ContractUtils.RequiresNotNull(indexes, "indexes"); 

            Type arrayType = array.Type; 
            if (!arrayType.IsArray) { 
                throw Error.ArgumentMustBeArray();
            } 

            ReadOnlyCollection indexList = indexes.ToReadOnly();
            if (arrayType.GetArrayRank() != indexList.Count) {
                throw Error.IncorrectNumberOfIndexes(); 
            }
 
            foreach (Expression e in indexList) { 
                RequiresCanRead(e, "indexes");
                if (e.Type != typeof(int)) { 
                    throw Error.ArgumentMustBeArrayIndexType();
                }
            }
 
            MethodInfo mi = array.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance);
            return Call(array, mi, indexList); 
        } 

        #endregion 

    }
}

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