public static object CreateInstance(Type instanceType, IServiceProvider services, params object[] parameters)
        {
            if (services == null)
            {
                return(CreateInstance(instanceType, parameters));
            }
            if (instanceType == null)
            {
                throw new ArgumentNullException(nameof(instanceType));
            }

            CheckInstanceTypeOrThrow(instanceType);

            if (instanceType.GetTypeInfo().IsPrimitive)
            {
                object value;
                if (parameters.Length > 0 && TryFindBestMatchOfPrimitive(instanceType, parameters, out value))
                {
                    return(value);
                }
                throw new InvalidOperationException($"primitive type {instanceType.Name} has no constructor");
            }

            ConstructorInfo[] constructors = instanceType.GetConstructorsFromCache();
            if (constructors.Length <= 0)
            {
                throw new InvalidOperationException($"cannot find any constructor to initialize instance of type {instanceType.Name}");
            }

            IEnumerable <ArgumentMatchedResult> matchResults = null;

            if (parameters.Length > 0)
            {
                matchResults = constructors.Select(m => ArgumentMatchedResult.Match(m, services, parameters));
            }
            else
            {
                matchResults = constructors.Select(m => ArgumentMatchedResult.Match(m, services));
            }

            ArgumentMatchedResult matchResult = FindBestMatch(matchResults);

            if (matchResult == null)
            {
                throw new InvalidOperationException($"cannot find any constructor of type {instanceType.Name} that matchs given parameters");
            }

            ConstructorInfo constructor = matchResult.Method as ConstructorInfo;

            try
            {
                object instance = constructor.Invoke(matchResult.Result);
                return(instance);
            }
            catch (TargetInvocationException ex)
            {
                ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
                throw;
            }
        }
        public static MethodInvokeContext CreateInvokeContext(MethodInfo method, IReadOnlyDictionary <string, object> options, params object[] parameters)
        {
            if (method == null)
            {
                throw new ArgumentNullException(nameof(method));
            }
            if (options == null)
            {
                return(CreateInvokeContext(method, parameters));
            }

            ArgumentMatchedResult matchResult = null;

            if (parameters.Length > 0)
            {
                matchResult = ArgumentMatchedResult.Match(method, options, parameters);
            }
            else
            {
                matchResult = ArgumentMatchedResult.Match(method, options);
            }

            if (!matchResult.IsPassed)
            {
                return(null);
            }
            return(new MethodInvokeContext(matchResult.Score, matchResult.Result, method));
        }
        public static MethodInvokeContext CreateInvokeContext(MethodInfo method, IServiceProvider services, params object[] parameters)
        {
            if (method == null)
            {
                throw new ArgumentNullException(nameof(method));
            }
            if (services == null)
            {
                return(CreateInvokeContext(method, parameters));
            }

            ArgumentMatchedResult matchResult = null;

            if (parameters.Length > 0)
            {
                matchResult = ArgumentMatchedResult.Match(method, services, parameters);
            }
            else
            {
                matchResult = ArgumentMatchedResult.Match(method, services);
            }

            if (!matchResult.IsPassed)
            {
                return(null);
            }
            return(new MethodInvokeContext(matchResult.Score, matchResult.Result, method));
        }
        public static object InvokeMethod(object instance, string methodName, IServiceProvider services, IReadOnlyDictionary <string, object> options, params object[] parameters)
        {
            if (instance == null)
            {
                throw new ArgumentNullException(nameof(instance));
            }
            if (methodName == null)
            {
                throw new ArgumentNullException(nameof(methodName));
            }
            if (options == null)
            {
                return(InvokeMethod(instance, methodName, services, parameters));
            }
            if (services == null)
            {
                return(InvokeMethod(instance, methodName, options, parameters));
            }

            Type instanceType = instance.GetType();

            MethodInfo[] methods = instanceType.GetMethodOverloads(methodName, false);
            if (methods.Length <= 0)
            {
                throw new InvalidOperationException("cannot find method {methodName} of instance {instance}");
            }

            IEnumerable <ArgumentMatchedResult> matchResults = null;

            if (parameters.Length > 0)
            {
                matchResults = methods.Select(m => ArgumentMatchedResult.Match(m, services, options, parameters));
            }
            else
            {
                matchResults = methods.Select(m => ArgumentMatchedResult.Match(m, services, options));
            }

            ArgumentMatchedResult matchResult = FindBestMatch(matchResults);

            if (matchResult == null)
            {
                throw new InvalidOperationException($"cannot find any method {methods[0].Name} of instance {instance} that matchs given parameters");
            }
            InvokeMethodResult result = TryInvokeMethod(instance, matchResult);

            if (result.IsExecutionSucceeded == false)
            {
                throw result.Exception;
            }
            if (result.HasReturnValueBySignature == false)
            {
                return(null);
            }
            else
            {
                return(result.ReturnValue);
            }
        }
        public static object InvokeMethod(object instance, MethodInfo method, IServiceProvider services, IReadOnlyDictionary <string, object> options, params object[] parameters)
        {
            if (instance == null)
            {
                throw new ArgumentNullException(nameof(instance));
            }
            if (method == null)
            {
                throw new ArgumentNullException(nameof(method));
            }
            if (options == null)
            {
                return(InvokeMethod(instance, method, services, parameters));
            }
            if (services == null)
            {
                return(InvokeMethod(instance, method, options, parameters));
            }

            ArgumentMatchedResult matchResult = null;

            if (parameters.Length > 0)
            {
                matchResult = ArgumentMatchedResult.Match(method, services, options, parameters);
            }
            else
            {
                matchResult = ArgumentMatchedResult.Match(method, services, options);
            }
            InvokeMethodResult result = TryInvokeMethod(instance, matchResult);

            if (result.IsExecuted == false)
            {
                throw new InvalidOperationException("cannot invoke method due to insufficient parameters");
            }
            if (result.IsExecutionSucceeded == false)
            {
                throw result.Exception;
            }
            if (result.HasReturnValueBySignature == false)
            {
                return(null);
            }
            else
            {
                return(result.ReturnValue);
            }
        }
        private static ArgumentMatchedResult FindBestMatch(IEnumerable <ArgumentMatchedResult> results)
        {
            double maxScore = 0;
            ArgumentMatchedResult matchResult = null;

            foreach (ArgumentMatchedResult m in results)
            {
                if (!m.IsPassed)
                {
                    continue;
                }
                if (m.Score > maxScore)
                {
                    matchResult = m;
                    maxScore    = m.Score;
                }
            }
            return(matchResult);
        }
        private static InvokeMethodResult TryInvokeMethod(object instance, ArgumentMatchedResult matchResult)
        {
            MethodInfo method = matchResult.Method as MethodInfo;

            if (!matchResult.IsPassed)
            {
                return(InvokeMethodResult.MethodNotFound());
            }

            try
            {
                object returnValue = method.Invoke(instance, matchResult.Result);
                return(InvokeMethodResult.Success(method.ReturnType, returnValue));
            }
            catch (TargetInvocationException ex)
            {
                return(InvokeMethodResult.Failed(ex.InnerException));
            }
            catch
            {
                throw;
            }
        }