/// <summary> /// Binds all the fields for the instance. /// </summary> private void BindFields(JsBinding binding, IHostType hostType, object instance) { // TODO: Seems like we can hoist this into JsInterop, which would allow us refactor // TODO: out the builder class completely. var fields = hostType.FieldNames; for (int i = 0; i < fields.Count; ++i) { var fieldName = fields[i]; binding.AddProperty( fieldName, (v, s, args, argLength, data) => { var fieldInfo = hostType.FieldFor(fieldName).Field; var result = fieldInfo.GetValue(instance); var returnType = JsConversions.TypeFor(result, fieldInfo.FieldType); return(_interop.ToJsObject(result, returnType)); }, (v, s, args, argLength, data) => { var fieldInfo = hostType.FieldFor(fieldName).Field; var fieldType = fieldInfo.FieldType; var value = _interop.ToHostObject(args[1], fieldType); fieldInfo.SetValue(instance, value); return(JavaScriptValue.Invalid); }); } }
/// <summary> /// Binds all public properties for the instance. /// </summary> private void BindProperties(JsBinding binding, IHostType hostType, object instance) { // TODO: Seems like we can hoist this into JsInterop, which would allow us refactor // TODO: out the builder class completely. var properties = hostType.PropertyNames; for (int i = 0; i < properties.Count; ++i) { var propertyName = properties[i]; binding.AddProperty( propertyName, (v, s, args, argLength, data) => { var get = hostType.PropertyFor(propertyName).Getter; var result = get.Invoke(instance, EmptyParameters); var returnType = JsConversions.TypeFor(result, get.ReturnType); return(_interop.ToJsObject(result, returnType)); }, (v, s, args, argLength, data) => { var hostProperty = hostType.PropertyFor(propertyName); var propType = hostProperty.PropertyType; var set = hostProperty.Setter; var value = _interop.ToHostObject(args[1], propType); set.Invoke(instance, new[] { value }); return(JavaScriptValue.Invalid); }); } }
/// <summary> /// Sets the host object to target when creating the binding. /// </summary> /// <param name="hostObject">The host object to use for the javascript binding.</param> /// <param name="type">The <see cref="Type"/> of the host object.</param> public JsBindingBuilder BoundTo(object hostObject, Type type) { _boundTo = hostObject; _hostType = TypeCache.Get(type); return(this); }
/// <summary> /// Adds function bindings for all methods in the <see cref="IHostType"/>. /// </summary> private void BindMethods(JsBinding binding, IHostType hostType, object instance) { // TODO: Seems like we can hoist this into JsInterop, which would allow us refactor // TODO: out the builder class completely. var methods = hostType.MethodNames; for (int i = 0; i < methods.Count; ++i) { var methodName = methods[i]; binding.AddFunction( methodName, (v, s, args, argLength, data) => { var totalParameters = argLength - 1; var hostMethods = hostType.MethodsFor(methodName, totalParameters); if (hostMethods.Count == 0) { var message = $"Calling host function that does not exist: [Method: {methodName}, Instance: {instance}]"; JsErrorHelper.SetJsException(message); return(JavaScriptValue.Invalid); } HostMethod hostMethodInfo; // Only a single method returned. Call this optimistically if (hostMethods.Count == 1) { hostMethodInfo = hostMethods[0]; } else { // Get the Parameter Key, and look up cached invocation var invokeKey = JsConversions.ToInvokeKey(methodName, args, argLength); if (!hostType.TryGetInvocation(invokeKey, out hostMethodInfo)) { // Otherwise, locate best method for these argument, and cache hostMethodInfo = FindBestMethod(hostMethods, args, argLength); hostType.CacheInvocation(invokeKey, hostMethodInfo); } } if (null == hostMethodInfo) { LogMethodSelectionFailure(hostMethods, args, argLength); JsErrorHelper.SetJsException( $"Calling host function that does not exist: [Method: {methodName}, Instance: {instance}]"); return(JavaScriptValue.Invalid); } try { var realParams = ToParameters(hostMethodInfo, args, argLength); var result = hostMethodInfo.Method.Invoke(instance, realParams); var resultType = hostMethodInfo.ReturnType; if (resultType == typeof(void)) { return(JavaScriptValue.Invalid); } resultType = JsConversions.TypeFor(result, resultType); return(_interop.ToJsObject(result, resultType)); } catch (Exception e) { LogMethodInvocationInfo(hostMethodInfo, instance); throw; } }); } }