예제 #1
0
 public CoercedAwaitableInfo(Expression coercerExpression, Type coercerResultType,
                             AwaitableInfo coercedAwaitableInfo)
 {
     CoercerExpression = coercerExpression;
     CoercerResultType = coercerResultType;
     AwaitableInfo     = coercedAwaitableInfo;
 }
예제 #2
0
        public static bool IsTypeAwaitable(Type type, out CoercedAwaitableInfo info)
        {
            if (AwaitableInfo.IsTypeAwaitable(type, out var directlyAwaitableInfo))
            {
                info = new CoercedAwaitableInfo(directlyAwaitableInfo);
                return(true);
            }

            // It's not directly awaitable, but maybe we can coerce it.
            // Currently we support coercing FSharpAsync<T>.
            if (ObjectMethodExecutorFSharpSupport.TryBuildCoercerFromFSharpAsyncToAwaitable(type, out Expression coercerExpression, out Type coercerResultType))
            {
                //if (AwaitableInfo.IsTypeAwaitable(coercerResultType, out var coercedAwaitableInfo))
                {
                    //    info = new CoercedAwaitableInfo(coercerExpression, coercerResultType, coercedAwaitableInfo);
                    //   return true;
                }
            }


            info = default(CoercedAwaitableInfo);
            return(false);
        }
 public CoercedAwaitableInfo(AwaitableInfo awaitableInfo)
 {
     AwaitableInfo     = awaitableInfo;
     CoercerExpression = null;
     CoercerResultType = null;
 }
예제 #4
0
        public static bool IsTypeAwaitable(Type type, out AwaitableInfo awaitableInfo)
        {
            // Based on Roslyn code: http://source.roslyn.io/#Microsoft.CodeAnalysis.Workspaces/Shared/Extensions/ISymbolExtensions.cs,db4d48ba694b9347

            // Awaitable must have method matching "object GetAwaiter()"
            var getAwaiterMethod = type.GetMethods().FirstOrDefault(m =>
                                                                    m.Name.Equals("GetAwaiter", StringComparison.OrdinalIgnoreCase) &&
                                                                    m.GetParameters().Length == 0 &&
                                                                    m.ReturnType != null);

            if (getAwaiterMethod == null)
            {
                awaitableInfo = default(AwaitableInfo);
                return(false);
            }

            var awaiterType = getAwaiterMethod.ReturnType;

            // Awaiter must have property matching "bool IsCompleted { get; }"
            var isCompletedProperty = awaiterType.GetProperties().FirstOrDefault(p =>
                                                                                 p.Name.Equals("IsCompleted", StringComparison.OrdinalIgnoreCase) &&
                                                                                 p.PropertyType.Equals(typeof(bool)) &&
                                                                                 p.GetMethod != null);

            if (isCompletedProperty == null)
            {
                awaitableInfo = default(AwaitableInfo);
                return(false);
            }

            // Awaiter must implement INotifyCompletion
            var awaiterInterfaces           = awaiterType.GetInterfaces();
            var implementsINotifyCompletion = awaiterInterfaces.Any(t => t.Equals(typeof(INotifyCompletion)));

            if (!implementsINotifyCompletion)
            {
                awaitableInfo = default(AwaitableInfo);
                return(false);
            }

            // INotifyCompletion supplies a method matching "void OnCompleted(Action action)"
            //var iNotifyCompletionMap = awaiterType
            //    .GetTypeInfo()
            //    .DeclaredMethods
            //    .GetRuntimeInterfaceMap(getType(typeof(INotifyCompletion)));
            var onCompletedMethod = awaiterType.GetMethods().Single(m =>
                                                                    m.Name.Equals("OnCompleted", StringComparison.OrdinalIgnoreCase) &&
                                                                    m.ReturnType.Equals(typeof(void)) &&
                                                                    m.GetParameters().Length == 1 &&
                                                                    m.GetParameters()[0].ParameterType.Equals(typeof(Action)));

            // Awaiter optionally implements ICriticalNotifyCompletion
            var        implementsICriticalNotifyCompletion = awaiterInterfaces.Any(t => t.Equals(typeof(ICriticalNotifyCompletion)));
            MethodInfo unsafeOnCompletedMethod;

            if (implementsICriticalNotifyCompletion)
            {
                // ICriticalNotifyCompletion supplies a method matching "void UnsafeOnCompleted(Action action)"
                //var iCriticalNotifyCompletionMap = awaiterType
                //    .GetTypeInfo()
                //    .GetRuntimeInterfaceMap(typeof(ICriticalNotifyCompletion));
                unsafeOnCompletedMethod = awaiterType.GetMethods().Single(m =>
                                                                          m.Name.Equals("UnsafeOnCompleted", StringComparison.OrdinalIgnoreCase) &&
                                                                          m.ReturnType.Equals(typeof(void)) &&
                                                                          m.GetParameters().Length == 1 &&
                                                                          m.GetParameters()[0].ParameterType.Equals(typeof(Action)));
            }
            else
            {
                unsafeOnCompletedMethod = null;
            }

            // Awaiter must have method matching "void GetResult" or "T GetResult()"
            var getResultMethod = awaiterType.GetMethods().FirstOrDefault(m =>
                                                                          m.Name.Equals("GetResult") &&
                                                                          m.GetParameters().Length == 0);

            if (getResultMethod == null)
            {
                awaitableInfo = default(AwaitableInfo);
                return(false);
            }

            awaitableInfo = new AwaitableInfo(
                awaiterType,
                isCompletedProperty,
                getResultMethod,
                onCompletedMethod,
                unsafeOnCompletedMethod,
                getResultMethod.ReturnType,
                getAwaiterMethod);
            return(true);
        }