/// <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); }