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