コード例 #1
0
ファイル: Emit.CallVirtual.cs プロジェクト: arlm/Sigil-vNext
        /// <summary>
        /// Calls the given method virtually.  Pops its arguments in reverse order (left-most deepest in the stack), and pushes the return value if it is non-void.
        ///
        /// The `this` reference should appear before any arguments (deepest in the stack).
        ///
        /// The method invoked at runtime is determined by the type of the `this` reference.
        ///
        /// If the method invoked shouldn't vary (or if the method is static), use Call instead.
        /// </summary>
        public Emit <DelegateType> CallVirtual(MethodInfo method, Type constrained = null, Type[] arglist = null)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }

            if (method.IsStatic)
            {
                throw new ArgumentException("Only non-static methods can be called using CallVirtual, found " + method);
            }

            if (HasFlag(method.CallingConvention, CallingConventions.VarArgs) && !HasFlag(method.CallingConvention, CallingConventions.Standard))
            {
                if (arglist == null)
                {
                    throw new InvalidOperationException("When calling a VarArgs method, arglist must be set");
                }
            }

            var expectedParams = ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => TypeOnStack.Get(s.ParameterType)).ToList();

            var declaring = method.DeclaringType;

            if (TypeHelpers.IsValueType(declaring))
            {
                declaring = declaring.MakePointerType();
            }

            // "this" parameter
            expectedParams.Insert(0, TypeOnStack.Get(declaring));

            if (arglist != null)
            {
                expectedParams.AddRange(LinqAlternative.Select(arglist, t => TypeOnStack.Get(t)));
            }

            var resultType = method.ReturnType == typeof(void) ? null : TypeOnStack.Get(method.ReturnType);

            // Shove the constrained prefix in if it's supplied
            if (constrained != null)
            {
                UpdateState(OpCodes.Constrained, constrained, Wrap(StackTransition.None(), "CallVirtual"));
            }

            IEnumerable <StackTransition> transitions;

            if (resultType != null)
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new [] { resultType })
                };
            }
            else
            {
                transitions =
                    new[]
                {
                    new StackTransition(expectedParams.Reverse().AsEnumerable(), new TypeOnStack[0])
                };
            }

            UpdateState(OpCodes.Callvirt, method, ((LinqArray <ParameterInfo>)method.GetParameters()).Select(s => s.ParameterType).AsEnumerable(), Wrap(transitions, "CallVirtual"), arglist: arglist);

            return(this);
        }