/// <summary>
        /// Initialize a new cached component filter
        /// </summary>
        /// <param name="componentList">The array of objects to use</param>
        /// <param name="includeDisabled">Whether to include components on disabled objects</param>
        public CachedComponentFilter(TFilterType[] componentList, bool includeDisabled = true)
        {
            if (componentList == null)
            {
                return;
            }

            m_MasterComponentStorage = CollectionPool <List <TFilterType>, TFilterType> .GetCollection();

            k_TempComponentList.Clear();
            k_TempComponentList.AddRange(componentList);
            FilteredCopyToMaster(includeDisabled);
        }
        /// <summary>
        /// Dispose of the cached component filter
        /// </summary>
        /// <param name="disposing">Whether or not to dispose the contents of this object</param>
        protected virtual void Dispose(bool disposing)
        {
            if (m_DisposedValue)
            {
                return;
            }

            if (disposing && m_MasterComponentStorage != null)
            {
                CollectionPool <List <TFilterType>, TFilterType> .RecycleCollection(m_MasterComponentStorage);
            }

            m_DisposedValue = true;
        }
        bool m_DisposedValue; // To detect redundant calls

        /// <summary>
        /// Initialize a new cached component filter
        /// </summary>
        /// <param name="componentRoot">The component at the root of the hierarchy</param>
        /// <param name="cachedSearchType">What type of hierarchy traversal to perform</param>
        /// <param name="includeDisabled">Whether to include components on disabled objects</param>
        public CachedComponentFilter(TRootType componentRoot, CachedSearchType cachedSearchType = CachedSearchType.Self | CachedSearchType.Children, bool includeDisabled = true)
        {
            m_MasterComponentStorage = CollectionPool <List <TFilterType>, TFilterType> .GetCollection();

            k_TempComponentList.Clear();
            k_TempHostComponentList.Clear();

            // Components on the root get added first
            if ((cachedSearchType & CachedSearchType.Self) == CachedSearchType.Self)
            {
                componentRoot.GetComponents(k_TempComponentList);
                componentRoot.GetComponents(k_TempHostComponentList);
                FilteredCopyToMaster(includeDisabled);
            }

            // Then parents, until/unless we hit an end cap node
            if ((cachedSearchType & CachedSearchType.Parents) == CachedSearchType.Parents)
            {
                var searchRoot = componentRoot.transform.parent;
                while (searchRoot != null)
                {
                    if (searchRoot.GetComponent <TRootType>() != null)
                    {
                        break;
                    }

                    searchRoot.GetComponents(k_TempComponentList);
                    searchRoot.GetComponents(k_TempHostComponentList);
                    FilteredCopyToMaster(includeDisabled);

                    searchRoot = searchRoot.transform.parent;
                }
            }

            // Then children, until/unless we hit an end cap node
            if ((cachedSearchType & CachedSearchType.Children) == CachedSearchType.Children)
            {
                // It's not as graceful going down the hierarchy, so we just use the built-in functions and filter afterwards
                foreach (Transform child in componentRoot.transform)
                {
                    child.GetComponentsInChildren(k_TempComponentList);
                    child.GetComponentsInChildren(k_TempHostComponentList);
                    FilteredCopyToMaster(includeDisabled, componentRoot);
                }
            }
        }
        /// <summary>
        /// Remove UnityObjects from a dictionary which have been destroyed
        /// </summary>
        /// <typeparam name="T">The specific type of UnityObject in the dictionary</typeparam>
        /// <param name="list">A dictionary of UnityObjects that may contain destroyed objects</param>
        public static void RemoveDestroyedObjects <T>(List <T> list) where T : UnityObject
        {
            var removeList = CollectionPool <List <T>, T> .GetCollection();

            foreach (var component in list)
            {
                if (component == null)
                {
                    removeList.Add(component);
                }
            }

            foreach (var entry in removeList)
            {
                list.Remove(entry);
            }

            CollectionPool <List <T>, T> .RecycleCollection(removeList);
        }
        /// <summary>
        /// Remove UnityObjects keys from a dictionary which have been destroyed
        /// </summary>
        /// <typeparam name="TKey">The specific type of UnityObject in the dictionary</typeparam>
        /// <typeparam name="TValue">The value type of the dictionary</typeparam>
        /// <param name="dictionary">A dictionary of UnityObjects that may contain destroyed objects</param>
        public static void RemoveDestroyedKeys <TKey, TValue>(Dictionary <TKey, TValue> dictionary) where TKey : UnityObject
        {
            var removeList = CollectionPool <List <TKey>, TKey> .GetCollection();

            foreach (var kvp in dictionary)
            {
                var key = kvp.Key;
                if (key == null)
                {
                    removeList.Add(key);
                }
            }

            foreach (var key in removeList)
            {
                dictionary.Remove(key);
            }

            CollectionPool <List <TKey>, TKey> .RecycleCollection(removeList);
        }