Exemplo n.º 1
0
        /// <summary>
        /// Invokes the method on o (potentially using a previous invoker as a hint).
        ///
        /// Note that this method works if the parameters haven been boxed, return value is also boxed.
        /// </summary>
        /// <param name="invoker">The previous invoker as a hint, null if we could not get the invoker during the fast path.</param>
        /// <param name="o">The target of the invocation.</param>
        private object ResolveAndInvoke(object o, bool invokeOnly)
        {
            // Property and same target, or same type has already been checked earlier (by the fast path)
            // So here we have a new target type, we have an overloading, or this is the first time
            // Parameters have been boxed and stored in mArgs already.

            // Note that if we are overloading, we still do a full CreateDelegate work, even if we had the same type, target and method...
            // This is slow, however it should pretty much never happen in game code.

            if ((mInvoker == null) && (invokeOnly == false))
            {
                // It means that we did not get the invoker from the fast path (overloaded - rare - or it is the first time - very common).
                var dc = o as IDynamicClass;
                if (dc != null)
                {
                    object value;
                    if (dc.__TryGetDynamicValue(mName, out value) && value is Delegate)
                    {
                        var func = value as Delegate;
                        // Assume that most time, it is due to the first execution, so don't compare with previous version
                        mInvoker   = ActionCreator.CreateInvoker(func);                         // This is going to use an invoker factory (can be registered by user too for more optimal code).
                        invokeOnly = true;
                    }
                }
            }
            if (invokeOnly)
            {
                Stats.Increment(StatsCounter.InvokeMemberBinderInvoked_Slow);

                return(mInvoker.SafeInvokeWith(mArgs));
            }

            // If we reached this point, we have to do a new resolve, then invoke

            // determine object type
            Type otype;
            bool isStatic;

            if (o is Type)
            {
                // this is a static method invocation where o is the class
                otype    = (Type)o;
                isStatic = true;
            }
            else
            {
                // this is a instance method invocation
                otype    = o.GetType();
                isStatic = false;
            }

            // see if type has changed
            if (otype != mType)
            {
                // re-resolve method list if type has changed
                mType = otype;

                // get method list for type and method name
                BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public;
                if (isStatic)
                {
                    flags |= BindingFlags.Static;
                }
                else
                {
                    flags |= BindingFlags.Instance;
                }

                mMethodList = MethodBinder.LookupMethodList(mType, mName, flags, mArgs.Length);

                // select new method to use, this will try to reuse
                mInvoker = SelectMethod(o);
            }
            else if (mOverloadState == OverloadState.HasOverload)
            {
                // if there are overloads we select the method every time
                // we could look into a more optimal way of doing this if it becomes a problem
                mInvoker = SelectMethod(o);
            }
            else
            {
                // Same instance type, no overload, so should be the same method (or none).
                // We might be able to update the invoker if only the target changed
                mInvoker = InvokerBase.UpdateOrCreate(mInvoker, o, mMethod.Method);
            }

            Stats.Increment(StatsCounter.InvokeMemberBinderInvoked_Slow);

            TypeLogger.LogType(o);

            return(mInvoker.SafeInvokeWith(mArgs));
        }
        private object ResolveAndInvoke(object o, int argCount)
        {
            // determine object type
            Type otype;
            bool isStatic;

            if (o is Type)
            {
                // this is a static method invocation where o is the class
                otype    = (Type)o;
                isStatic = true;
            }
            else
            {
                // this is a instance method invocation
                otype    = o.GetType();
                isStatic = false;
            }

            // see if type has changed
            if (otype != mType)
            {
                // re-resolve method list if type has changed
                mType = otype;

                // get method list for type and method name
                BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public;
                if (isStatic)
                {
                    flags |= BindingFlags.Static;
                }
                else
                {
                    flags |= BindingFlags.Instance;
                }

                mMethodList = MethodBinder.LookupMethodList(mType, this.name, flags, argCount);

                // select new method to use
                SelectMethod(o, argCount);
            }
            else if (mIsOverloaded)
            {
                // if there are overloads we select the method every time
                // we could look into a more optimal way of doing this if it becomes a problem
                SelectMethod(o, argCount);
            }

            if (mDelegate == null)
            {
                // invoke as method
                // convert arguments for method
                if (mMethod.ConvertArguments(o, mArgs, argCount, ref mConvertedArgs))
                {
                    // invoke method with converted arguments
                    return(mMethod.Method.Invoke(o, mConvertedArgs));
                }
            }
            else
            {
                // invoke as delegate
                // convert arguments for delegate and invoke
                object[] newargs = PlayScript.Dynamic.ConvertArgumentList(mDelegate.Method, mArgs);
                return(mDelegate.DynamicInvoke(newargs));
            }

            throw new InvalidOperationException("Could not find suitable method to invoke: " + this.name + " for type: " + mType);
        }