/// <summary>
        /// WARNING: Pubternal API (internal). Do not use. May change during any update.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <param name="types"></param>
        /// <returns></returns>
        public static CachedMethod CachedMethod(this Type type, string name, params Type[] types)
        {
            var key = new MemberLookupKey(type, name);

            if (!Methods.TryGetValue(key, out var cachedMember))
            {
                var        currentType = type;
                MethodInfo method      = null;

                while (method == null && currentType != null)
                {
                    if (types == null || types.Length == 0)
                    {
                        method = currentType.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                    }
                    else
                    {
                        method = currentType.GetMethod(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, types, null);
                    }
                    currentType = currentType.BaseType;
                }

                if (method != null)
                {
                    cachedMember = new CachedMethod(method);
                }

                // also cache nulls!
                Methods[key] = cachedMember;
            }

            return(cachedMember);
        }
        /// <summary>
        /// WARNING: Pubternal API (internal). Do not use. May change during any update.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static CachedProperty CachedProperty(this Type type, string name)
        {
            var key = new MemberLookupKey(type, name);

            if (!Properties.TryGetValue(key, out var cachedMember))
            {
                var          currentType = type;
                PropertyInfo property    = null;

                while (property == null && currentType != null)
                {
                    property    = currentType.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                    currentType = currentType.BaseType;
                }

                if (property != null)
                {
                    cachedMember = new CachedProperty(property);
                }

                // also cache nulls!
                Properties[key] = cachedMember;
            }

            return(cachedMember);
        }
        /// <summary>
        /// WARNING: Pubternal API (internal). Do not use. May change during any update.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static CachedField CachedField(this Type type, string name)
        {
            var key = new MemberLookupKey(type, name);

            if (!Fields.TryGetValue(key, out var cachedMember))
            {
                var       currentType = type;
                FieldInfo field       = null;

                while (field == null && currentType != null)
                {
                    field       = currentType.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
                    currentType = currentType.BaseType;
                }

                if (field != null)
                {
                    cachedMember = new CachedField(field);
                }

                // also cache nulls!
                Fields[key] = cachedMember;
            }

            return(cachedMember);
        }