예제 #1
0
        /// <summary>
        /// Returns a delegate that will attempt to coerce supplied arguments into the specified delegate and return the result.
        /// </summary>
        /// <param name="func"></param>
        /// <returns></returns>
        private JavaScriptNativeFunction CreateNativeFunctionForDelegate(Delegate func)
        {
            //This is crazy fun.
            var funcParams = func.Method.GetParameters();
            JavaScriptNativeFunction fnDelegate = (IntPtr callee, bool isConstructCall, IntPtr[] arguments, ushort argumentCount, IntPtr callbackData) =>
            {
                //Make sure that we have argument values for each parameter.
                var nativeArgs = new object[funcParams.Length];
                for (int i = 0; i < funcParams.Length; i++)
                {
                    var targetParameterType = funcParams[i].ParameterType;

                    var currentArgument = arguments.ElementAtOrDefault(i);
                    if (currentArgument == default(IntPtr))
                    {
                        //If the argument wasn't specified, use the default value for the target parameter.
                        nativeArgs[i] = targetParameterType.GetDefaultValue();
                    }
                    else
                    {
                        //As the argument has been specified, convert the JsValue back to an Object using
                        //the conversion strategy associated with the context.

                        var argValueHandle = new JavaScriptValueSafeHandle(currentArgument);
                        var jsValue        = CreateValue(argValueHandle);
                        //Keep the first argument as the this JsObject.
                        if (i == 0)
                        {
                            nativeArgs[i] = jsValue as JsObject;
                        }
                        //If the target type is the same as the value type (The delegate expects a JsValue) don't convert.
                        else if (targetParameterType.IsSameOrSubclass(jsValue.GetType()))
                        {
                            nativeArgs[i] = jsValue;
                        }
                        else if (Context.Converter.TryToObject(Context, jsValue, out object obj))
                        {
                            try
                            {
                                nativeArgs[i] = Convert.ChangeType(obj, targetParameterType);
                            }
                            catch (Exception)
                            {
                                //Something went wrong, use the default value.
                                nativeArgs[i] = targetParameterType.GetDefaultValue();
                            }
                        }
                        else
                        {
                            //If we couldn't convert the type, use the default value.
                            nativeArgs[i] = targetParameterType.GetDefaultValue();
                        }
                    }
                }

                try
                {
                    var nativeResult = func.DynamicInvoke(nativeArgs);
                    if (Context.Converter.TryFromObject(Context, nativeResult, out JsValue valueResult))
                    {
                        return(valueResult.Handle.DangerousGetHandle());
                    }
                    else
                    {
                        return(Context.Undefined.Handle.DangerousGetHandle());
                    }
                }
                catch (TargetInvocationException exceptionResult)
                {
                    var jsError = CreateError(exceptionResult.InnerException);
                    m_engine.JsSetException(jsError.Handle);
                    return(Context.Undefined.Handle.DangerousGetHandle());
                }
            };

            return(fnDelegate);
        }