示例#1
0
        // 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);
        }