/// <summary>
        /// Gets a context value local to a drawer type for a given key, and creates a new instance of <see cref="T" />
        /// as a default value if the context doesn't already exist.
        /// </summary>
        /// <returns>Returns true if a new context was created.</returns>
        public bool Get <TValue, TDrawer>(string key, out PropertyContext <TValue> context)
        {
            bool isNew;

            this.TryGetDrawerContext(typeof(TDrawer), key, out context, out isNew);

            return(isNew);
        }
        /// <summary>
        /// Gets a context value local to a drawer type for a given key, and creates a new instance of <see cref="T" />
        /// as a default value if the context doesn't already exist.
        /// </summary>
        /// <returns>Returns true if a new context was created.</returns>
        public bool Get <TValue>(Type drawerType, string key, out PropertyContext <TValue> context)
        {
            bool isNew;

            this.TryGetDrawerContext(drawerType, key, out context, out isNew);

            return(isNew);
        }
        /// <summary>
        /// Gets a context value local to a drawer type for a given key, and creates a new instance of <see cref="T" />
        /// as a default value if the context doesn't already exist.
        /// </summary>
        /// <returns>Returns true if a new context was created.</returns>
        public bool Get <TValue>(OdinDrawer drawerInstance, string key, out PropertyContext <TValue> context)
        {
            bool isNew;

            this.TryGetDrawerContext(drawerInstance.GetType(), key, out context, out isNew);

            return(isNew);
        }
        protected override InspectorPropertyInfo[] GetPropertyInfos()
        {
            this.targetType = this.ValueEntry.TypeOfValue;
            var members = targetType.GetAllMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            var infos   = new List <InspectorPropertyInfo>();

            this.allowObsoleteMembers = this.Property.Context.GetGlobal("ALLOW_OBSOLETE_STATIC_MEMBERS", false);

            foreach (var member in members.Where(Filter).OrderBy(Order))
            {
                var attributes = new List <Attribute>();
                InspectorPropertyInfoUtility.ProcessAttributes(this.Property, member, attributes);

                if (member is MethodInfo && !attributes.HasAttribute <ButtonAttribute>() && !attributes.HasAttribute <OnInspectorGUIAttribute>())
                {
                    attributes.Add(new ButtonAttribute(ButtonSizes.Medium));
                }

                var info = InspectorPropertyInfo.CreateForMember(member, true, SerializationBackend.None, attributes);

                InspectorPropertyInfo previousPropertyWithName = null;
                int previousPropertyIndex = -1;

                for (int j = 0; j < infos.Count; j++)
                {
                    if (infos[j].PropertyName == info.PropertyName)
                    {
                        previousPropertyIndex    = j;
                        previousPropertyWithName = infos[j];
                        break;
                    }
                }

                if (previousPropertyWithName != null)
                {
                    bool createAlias = true;

                    if (member.SignaturesAreEqual(previousPropertyWithName.GetMemberInfo()))
                    {
                        createAlias = false;
                        infos.RemoveAt(previousPropertyIndex);
                    }

                    if (createAlias)
                    {
                        var alias = InspectorPropertyInfoUtility.GetPrivateMemberAlias(previousPropertyWithName.GetMemberInfo(), previousPropertyWithName.TypeOfOwner.GetNiceName(), " -> ");
                        infos[previousPropertyIndex] = InspectorPropertyInfo.CreateForMember(alias, true, SerializationBackend.None, attributes);
                    }
                }

                infos.Add(info);
            }

            return(InspectorPropertyInfoUtility.BuildPropertyGroupsAndFinalize(this.Property, targetType, infos, false));
        }
        private bool TryGetGlobalConfig <T>(string key, out PropertyContext <T> context, out bool isNew)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            context = null;
            object value;

            if (this.globalContexts == null)
            {
                this.globalContexts = new Dictionary <string, object>();
            }

            var contexts = this.globalContexts;

            if (contexts.TryGetValue(key, out value))
            {
                isNew   = false;
                context = value as PropertyContext <T>;

                if (context == null)
                {
                    throw new InvalidOperationException("Tried to get global property of type " + typeof(T).GetNiceName() + " with key " + key + " on property at path " + this.property.Path + ", but a global property of a different type (" + value.GetType().GetArgumentsOfInheritedOpenGenericClass(typeof(PropertyContext <>))[0].GetNiceName() + ") already existed with the same key.");
                }
            }
            else
            {
                isNew   = true;
                context = PropertyContext <T> .Create();

                contexts[key] = context;
            }

            return(true);
        }
        private bool TryGetDrawerContext <T>(Type drawerType, string key, out PropertyContext <T> context, out bool isNew)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            if (drawerType == null)
            {
                throw new ArgumentNullException("drawerType");
            }

            object value;

            var contexts = this.GetCurrentDrawerContexts();

            if (contexts.TryGetInnerValue(drawerType, key, out value))
            {
                isNew   = false;
                context = value as PropertyContext <T>;

                if (context == null)
                {
                    throw new InvalidOperationException("Tried to get drawer property of type " + typeof(T).GetNiceName() + " with key " + key + " for drawer " + drawerType.GetNiceName() + " on property at path " + this.property.Path + ", but a drawer property for the same drawer type, of a different value type (" + value.GetType().GetArgumentsOfInheritedOpenGenericClass(typeof(PropertyContext <>))[0].GetNiceName() + ") already existed with the same key.");
                }
            }
            else
            {
                isNew   = true;
                context = PropertyContext <T> .Create();

                contexts[drawerType][key] = context;
            }

            return(true);
        }