private static void FindDrawerProviderForAttributesInTypes([NotNull] IEnumerable <Type> types)
        {
            foreach (var type in types)
            {
                if (!typeof(IDrawerProvider).IsAssignableFrom(type))
                {
                    continue;
                }

                foreach (var drawerProviderFor in AttributeUtility.GetAttributes <DrawerProviderForAttribute>(type))
                {
                    var inspectorType = drawerProviderFor.inspectorType;
                    if (inspectorType == null)
                    {
                        UnityEngine.Debug.LogError(drawerProviderFor.GetType().Name + " on class " + type.Name + " NullReferenceException - inspectorType was null!");
                        continue;
                    }

                    IDrawerProvider drawerProvider;
                    if (!drawerProvidersByInspectorType.TryGetValue(inspectorType, out drawerProvider) || !drawerProviderFor.isFallback)
                    {
                        bool reusedExistingInstance = false;
                        foreach (var createdDrawerProvider in drawerProvidersByInspectorType.Values)
                        {
                            if (createdDrawerProvider.GetType() == type)
                            {
                                drawerProvidersByInspectorType.Add(inspectorType, createdDrawerProvider);
                                reusedExistingInstance = true;
                                break;
                            }
                        }

                        if (!reusedExistingInstance)
                        {
                                                        #if DEV_MODE && DEBUG_SETUP
                            UnityEngine.Debug.Log("Creating new DrawerProvider instance of type " + type.Name + " for inspector" + inspectorType.Name);
                                                        #endif

                                                        #if DEV_MODE
                            var timer = new ExecutionTimeLogger();
                            timer.Start(type.Name + ".CreateInstance");
                                                        #endif

                            var drawerProviderInstance = (IDrawerProvider)Activator.CreateInstance(type);

                                                        #if DEV_MODE && PI_ASSERTATIONS
                            UnityEngine.Debug.Assert(drawerProviderInstance != null);
                                                        #endif

                            drawerProvidersByInspectorType.Add(inspectorType, drawerProviderInstance);

                                                        #if DEV_MODE && PI_ASSERTATIONS
                            UnityEngine.Debug.Assert(drawerProvidersByInspectorType[inspectorType] != null);
                                                        #endif

                                                        #if DEV_MODE
                            timer.FinishAndLogResults();
                                                        #endif
                        }
                    }
                }
            }
        }
        private static void SetupThreaded(object threadTaskId)
        {
                        #if DEV_MODE
            var timer = new ExecutionTimeLogger();
            timer.Start("DefaultDrawerProviders.SetupThreaded");
                        #endif

            drawerProvidersByInspectorTypeRebuilt = new Dictionary <Type, IDrawerProvider>(2);

                        #if DEV_MODE
            timer.StartInterval("FindDrawerProviderForAttributesInTypes");
                        #endif

            foreach (var type in TypeExtensions.GetAllTypesThreadSafe(false, true, true))
            {
                if (!typeof(IDrawerProvider).IsAssignableFrom(type))
                {
                    continue;
                }

                foreach (var drawerProviderFor in AttributeUtility.GetAttributes <DrawerProviderForAttribute>(type))
                {
                    var inspectorType = drawerProviderFor.inspectorType;
                    if (inspectorType == null)
                    {
                        UnityEngine.Debug.LogError(drawerProviderFor.GetType().Name + " on class " + type.Name + " NullReferenceException - inspectorType was null!");
                        continue;
                    }

                    IDrawerProvider drawerProvider;
                    if (!drawerProvidersByInspectorTypeRebuilt.TryGetValue(inspectorType, out drawerProvider) || !drawerProviderFor.isFallback)
                    {
                        bool reusedExistingInstance = false;
                        foreach (var createdDrawerProvider in drawerProvidersByInspectorTypeRebuilt.Values)
                        {
                            if (createdDrawerProvider.GetType() == type)
                            {
                                drawerProvidersByInspectorTypeRebuilt.Add(inspectorType, createdDrawerProvider);
                                reusedExistingInstance = true;
                                break;
                            }
                        }

                        if (!reusedExistingInstance)
                        {
                                                        #if DEV_MODE && DEBUG_SETUP
                            UnityEngine.Debug.Log("Creating new DrawerProvider instance of type " + type.Name + " for inspector" + inspectorType.Name);
                                                        #endif

                                                        #if DEV_MODE
                            timer.StartInterval(type.Name + ".CreateInstance");
                                                        #endif

                            var drawerProviderInstance = (IDrawerProvider)Activator.CreateInstance(type);

                                                        #if DEV_MODE && PI_ASSERTATIONS
                            UnityEngine.Debug.Assert(drawerProviderInstance != null);
                                                        #endif

                            drawerProvidersByInspectorTypeRebuilt.Add(inspectorType, drawerProviderInstance);

                                                        #if DEV_MODE && PI_ASSERTATIONS
                            UnityEngine.Debug.Assert(drawerProvidersByInspectorTypeRebuilt[inspectorType] != null);
                                                        #endif

                                                        #if DEV_MODE
                            timer.FinishInterval();
                                                        #endif
                        }
                    }
                }
            }

                        #if DEV_MODE
            timer.FinishInterval();
            timer.StartInterval("Add derived types");
                        #endif

            // Also add derived types of inspector types
            var addDerived = new List <KeyValuePair <Type, IDrawerProvider> >();
            foreach (var drawerByType in drawerProvidersByInspectorTypeRebuilt)
            {
                var exactInspectorType    = drawerByType.Key;
                var derivedInspectorTypes = exactInspectorType.IsInterface ? TypeExtensions.GetImplementingTypes(exactInspectorType, true) : TypeExtensions.GetExtendingTypes(exactInspectorType, true);
                for (int n = derivedInspectorTypes.Length - 1; n >= 0; n--)
                {
                    addDerived.Add(new KeyValuePair <Type, IDrawerProvider>(derivedInspectorTypes[n], drawerByType.Value));
                }
            }

            for (int n = addDerived.Count - 1; n >= 0; n--)
            {
                var add = addDerived[n];
                var derivedInspectorType = add.Key;
                if (!drawerProvidersByInspectorTypeRebuilt.ContainsKey(derivedInspectorType))
                {
                    drawerProvidersByInspectorTypeRebuilt.Add(derivedInspectorType, add.Value);
                }
            }

                        #if DEV_MODE && PI_ASSERTATIONS
            UnityEngine.Debug.Assert(drawerProvidersByInspectorTypeRebuilt[typeof(PowerInspector)] != null);
                        #endif

            //selfReady = true;
            threadedFullRebuildFinished = true;

                        #if DEV_MODE
            timer.FinishInterval();
            timer.FinishAndLogResults();
                        #endif

                        #if CACHE_TO_DISK && (!NET_2_0 && !NET_2_0_SUBSET && !NET_STANDARD_2_0) // HashSet.GetObjectData is not implemented in older versions
            EditorApplication.delayCall += Serialize;
                        #endif
        }