static bool ParamArrayMatchs(object[] args, int index, Type dest, ArgumentConversions conversions)
        {
            var argConversions = new ArgumentConversions(args.Length - index);

            // check first parameter type matches
            for (int i = 0, current = index; current < args.Length; i++, current++)
            {
                var arg = args[current];
                if (arg is null)
                {
                    if (dest.IsValueType && !IsNullableType(dest))
                    {
                        return(false);
                    }
                }
                else
                {
                    var src = arg.GetType();
                    if (!TypeUtils.AreReferenceAssignable(dest, src))
                    {
                        if (TryImplicitConvert(src, dest, out MethodInfo opImplict) == false)
                        {
                            return(false);
                        }
                        argConversions.Add(new ParamConversion(i, opImplict));
                    }
                }
            }
            conversions.Add(new ParamArrayConversion(index, dest, argConversions));
            return(true);
        }
        public static bool MatchesArguments(this MethodBase method, object[] args, ArgumentConversions conversions)
        {
            var parameters = method.GetParameters();
            // arg length
            var length = args.Length;
            // no arg
            int argCount = parameters.Length;

            if (argCount == 0 && length > 0)
            {
                return(false);
            }
            int i;

            for (i = 0; i < argCount; i++)
            {
                var param = parameters[i];
                var dest  = param.ParameterType;
                if (param.IsDefined(typeof(ParamArrayAttribute), false))
                {
                    // parameters is extra example print(string, params string[] args) and print('hello')
                    // in this case 2 and 1
                    if (argCount > length)
                    {
                        conversions.Add(new ParamArrayConversion(i, dest.GetElementType()));
                        return(true);
                    }
                    //No further check required if matchs
                    return(ParamArrayMatchs(args, i, dest.GetElementType(), conversions));
                }
                // matches current index
                if (i >= length)
                {
                    // method has one more parameter so skip
                    return(conversions.Recycle());
                }

                var arg = args[i];
                if (arg is null)
                {
                    if (dest.IsValueType && !IsNullableType(dest))
                    {
                        return(conversions.Recycle());
                    }
                }
                else
                {
                    var src = arg.GetType();
                    if (!TypeUtils.AreReferenceAssignable(dest, src))
                    {
                        if (TryImplicitConvert(src, dest, out MethodInfo opImplict) == false)
                        {
                            return(conversions.Recycle());
                        }
                        conversions.Add(new ParamConversion(i, opImplict));
                    }
                }
            }
            if (i == length)
            {
                return(true);
            }
            return(conversions.Recycle());
        }