예제 #1
0
        private void ConfigureMethod(MethodInfo method, ParameterInfo[] parameters)
        {
            var returnType = method.ReturnType;
            var isVoid     = returnType == typeof(void);

            if (isVoid)
            {
                _dispatchType    |= DispatchType.Void;
                LogicalReturnType = returnType;
            }
            else if (typeof(Promise).IsAssignableFrom(returnType))
            {
                _dispatchType |= DispatchType.Promise;
                var promise = returnType.GetOpenTypeConformance(typeof(Promise <>));
                LogicalReturnType = promise != null
                    ? promise.GetGenericArguments()[0]
                    : typeof(object);
            }
            else if (typeof(Task).IsAssignableFrom(returnType))
            {
                _dispatchType |= DispatchType.Task;
                var task = returnType.GetOpenTypeConformance(typeof(Task <>));
                LogicalReturnType = task != null
                    ? task.GetGenericArguments()[0]
                    : typeof(object);
            }
            else
            {
                LogicalReturnType = returnType;
            }

            if (!method.IsGenericMethodDefinition)
            {
                switch (parameters.Length)
                {
                    #region Early Bound
                case 0:
                    _delegate = isVoid
                                   ? (Delegate)RuntimeHelper.CreateCallNoArgs(method)
                                   : RuntimeHelper.CreateFuncNoArgs(method);
                    _dispatchType |= DispatchType.FastNoArgs;
                    return;

                case 1:
                    _delegate = isVoid
                                  ? (Delegate)RuntimeHelper.CreateCallOneArg(method)
                                  : RuntimeHelper.CreateFuncOneArg(method);
                    _dispatchType |= DispatchType.FastOneArg;
                    return;

                case 2:
                    _delegate = isVoid
                                  ? (Delegate)RuntimeHelper.CreateCallTwoArgs(method)
                                  : RuntimeHelper.CreateFuncTwoArgs(method);
                    _dispatchType |= DispatchType.FastTwoArgs;
                    return;

                case 3:
                    _delegate = isVoid
                                  ? (Delegate)RuntimeHelper.CreateCallThreeArgs(method)
                                  : RuntimeHelper.CreateFuncThreeArgs(method);
                    _dispatchType |= DispatchType.FastThreeArgs;
                    return;

                case 4:
                    _delegate = isVoid
                                  ? (Delegate)RuntimeHelper.CreateCallFourArgs(method)
                                  : RuntimeHelper.CreateFuncFourArgs(method);
                    _dispatchType |= DispatchType.FastFourArgs;
                    return;

                case 5:
                    _delegate = isVoid
                                  ? (Delegate)RuntimeHelper.CreateCallFiveArgs(method)
                                  : RuntimeHelper.CreateFuncFiveArgs(method);
                    _dispatchType |= DispatchType.FastFiveArgs;
                    return;

                    #endregion
                default:
                    _dispatchType |= DispatchType.LateBound;
                    return;
                }
            }

            var argSources = parameters
                             .Where(p => p.ParameterType.ContainsGenericParameters)
                             .Select(p => Tuple.Create(p.Position, p.ParameterType))
                             .ToList();
            if (returnType.ContainsGenericParameters)
            {
                if (IsAsync)
                {
                    returnType = returnType.GenericTypeArguments[0];
                }
                argSources.Add(Tuple.Create(UseReturn, returnType));
            }
            var methodArgs  = method.GetGenericArguments();
            var typeMapping = new Tuple <int, int> [methodArgs.Length];
            foreach (var source in argSources)
            {
                var sourceArg = source.Item2;
                if (sourceArg.IsGenericParameter)
                {
                    if (methodArgs.Length == 1 && methodArgs[0] == sourceArg)
                    {
                        typeMapping[0] = Tuple.Create(source.Item1, UseArgument);
                    }
                    continue;
                }
                var sourceGenericArgs = sourceArg.GetGenericArguments();
                for (var i = 0; i < methodArgs.Length; ++i)
                {
                    if (typeMapping[i] != null)
                    {
                        continue;
                    }
                    var index = Array.IndexOf(sourceGenericArgs, methodArgs[i]);
                    if (index >= 0)
                    {
                        typeMapping[i] = Tuple.Create(source.Item1, index);
                    }
                }
                if (!typeMapping.Contains(null))
                {
                    break;
                }
            }
            if (typeMapping.Contains(null))
            {
                throw new InvalidOperationException(
                          $"Type mapping for {method.GetDescription()} could not be inferred");
            }

            _mapping       = typeMapping;
            _dispatchType |= DispatchType.LateBound;
            _closed        = new ConcurrentDictionary <MethodInfo, MethodDispatch>();
        }