public bool Equals(JsDynamicObject other) { if (other is null) { return(false); } if (Handle.Type != other.Handle.Type) { return(false); } System.Diagnostics.Debug.Assert(Handle.Type == JsType.Object || Handle.Type == JsType.Function, "Only objects are supported by JsDynamicObject atm."); CheckDisposed(); // TODO: Do this using a native method, which would be more efficient. var gObj = _host.GetMember(JsValue.Global, "Object"); try { var result = _host.InvokeByName("is", gObj, 2, new DotNetValue[] { DotNetValue.FromJsValue(Handle), DotNetValue.FromJsValue(other.Handle) }); return(result.TryGetObject(_host, typeof(bool), out object resultObj) && (bool)resultObj); } finally { _host.Release(gObj); } }
public override bool TrySetMember(SetMemberBinder binder, object value) { CheckDisposed(); _host.SetMember(Handle, binder.Name, DotNetValue.FromObject(value, _host)); return(true); }
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) { if (indexes.Length != 1) { throw new InvalidOperationException("We only support single parameter indexer"); } CheckDisposed(); var index = indexes[0]; if (index == null) { throw new ArgumentNullException(nameof(index)); } if (index is string stringIndex) { _host.SetMember(Handle, stringIndex, DotNetValue.FromObject(value, _host)); return(true); } /*if (index is int intIndex) * { * var jsHandle = _host.SetMemberByIndex(Handle, intIndex); * return true; * }*/ return(base.TrySetIndex(binder, indexes, value)); }
public dynamic CreateNewInstance(params object[] arguments) { var result = _host.CreateObject(Handle, arguments.Select(a => DotNetValue.FromObject(a, _host)).ToArray()); if (!result.TryGetObject(_host, typeof(object), out object newInstance)) { throw new InvalidOperationException("Could not create new instance"); } return(newInstance); }
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { CheckDisposed(); var resultHandle = _host.Invoke(Handle, Handle, args.Length, args.Select(a => DotNetValue.FromObject(a, _host)).ToArray()); resultHandle.TryGetObject(_host, binder.ReturnType, out result); return(true); }
private static DotNetValue DynamicInvoke(Delegate @delegate, IHostInProcess host, JsValue[] argv) { var requiredParameters = @delegate.Method.GetParameters(); if (requiredParameters.Length > argv.Length) { foreach (var toRelease in argv) { host.Release(toRelease); } // This exception will be passed properly to JS throw new InvalidOperationException($"We need at least {requiredParameters.Length} arguments!"); } var mappedArgs = new object[requiredParameters.Length]; for (var c = 0; c < requiredParameters.Length; c++) { var paramType = requiredParameters[c].ParameterType; if (!argv[c].TryGetObject(host, paramType, out object parameter)) { // Release remaining arguments foreach (var toRelease in argv.Skip(c + 1)) { host.Release(toRelease); } throw new InvalidOperationException($"Cannot get {paramType.FullName} from JS handle of type {argv[c].Type}"); } mappedArgs[c] = parameter; } // Release remaining arguments foreach (var toRelease in argv.Skip(mappedArgs.Length)) { host.Release(toRelease); } var resultObj = @delegate.DynamicInvoke(mappedArgs); return(DotNetValue.FromObject(resultObj, host)); }
private DotNetValue InvokeDelegate(JsValue[] argv) { ReleaseRemainingArgs(argv, 0); return(DotNetValue.FromObject(_func(), Host)); }
// TODO DM 24.11.2019: This would require another bunch of reflection code to get working... /* * public TaskAwaiter GetAwaiter() * { * if (TryConvertIntern(typeof(Task), out object task)) * { * return ((Task)task).GetAwaiter(); * } * throw new InvalidOperationException("JS object is not awaitable"); * }*/ internal bool TryConvertIntern(Type type, out object result) { // Converting to string. if (type == typeof(object) || type.IsAssignableFrom(GetType())) { result = this; return(true); } //Console.WriteLine($"Converting to {type.Name}"); if (type == typeof(string)) { var jsResult = _host.InvokeByName("String", JsValue.Global, 1, new DotNetValue[] { DotNetValue.FromJsValue(Handle) }); var gotString = jsResult.TryGetObject(_host, typeof(string), out result); if (!gotString) { return(false); } return(result is string); } if (typeof(Task).IsAssignableFrom(type)) { var thenHandle = _host.GetMember(Handle, "then"); try { // Ensure that Handle is a thenable/promise like object if (thenHandle.Type == JsType.Function) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task <>)) { // TODO DM 24.11.2019: This is inefficient. We need to do this in the native code somehow... // How about _host.AttachTaskToPromise(Action<JsValue>,Action<JsValue>)? var resultType = type.GetGenericArguments()[0]; var completionSourceType = typeof(TaskCompletionSource <>).MakeGenericType(resultType); var tcs = Activator.CreateInstance(completionSourceType); var resolve = Delegate.CreateDelegate(typeof(Action <>).MakeGenericType(resultType), tcs, completionSourceType.GetMethod(nameof(TaskCompletionSource <object> .SetResult))); var reject = new Action <object>(error => { completionSourceType.GetMethod(nameof(TaskCompletionSource <object> .SetException)) .Invoke(tcs, new object[] { GetExceptionFromPromiseRejection(error) }); }); var thenResult = _host.Invoke(thenHandle, Handle, 2, new[] { DotNetValue.FromDelegate(resolve, _host), DotNetValue.FromDelegate(reject, _host) }); // DM 29.11.2019: thenResult is always another promise _host.Release(thenResult); result = completionSourceType.GetProperty(nameof(TaskCompletionSource <object> .Task)) .GetValue(tcs); return(true); } else { var tcs = new TaskCompletionSource <object>(); var thenResult = _host.Invoke(thenHandle, Handle, 2, new DotNetValue[] { DotNetValue.FromDelegate(new Action(() => tcs.SetResult(null)), _host), DotNetValue.FromDelegate(new Action <object>((error) => { tcs.SetException(GetExceptionFromPromiseRejection(error)); }), _host) }); // DM 29.11.2019: thenResult is always another promise _host.Release(thenResult); result = tcs.Task; return(true); } } } finally { _host.Release(thenHandle); } result = null; return(false); } if (typeof(Exception).IsAssignableFrom(type)) { dynamic dynamic = this; string stack = dynamic.stack; if (stack != null) { result = new InvalidOperationException($"JS Error:\n{stack}"); return(true); } result = null; return(false); } if (type.IsArray) { var innerType = type.GetElementType(); if (TryConvertToArray(innerType, out result)) { return(true); } result = null; return(false); } if (type.IsGenericType && type.IsInterface) { var unclosed = type.GetGenericTypeDefinition(); if (unclosed == typeof(IEnumerable <>) || unclosed == typeof(IReadOnlyCollection <>)) { var innerType = type.GetGenericArguments()[0]; if (TryConvertToArray(innerType, out result)) { return(true); } } result = null; return(false); } result = null; return(false); }