using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace QFSW.QC { /// /// Prevents the type from being loaded by an InjectionLoader /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class NoInjectAttribute : Attribute { } /// /// Loads and instantiates instances of the injectable types. /// /// The base type for the instances that will be injected. public class InjectionLoader { private Type[] _injectableTypes; /// /// Retrieves all of the injectable types. /// /// Forces a reload of the types instead of using the cache. /// The injectable types. public Type[] GetInjectableTypes(bool forceReload = false) { if (_injectableTypes == null || forceReload) { #if UNITY_2019_2_OR_NEWER && UNITY_EDITOR _injectableTypes = UnityEditor.TypeCache.GetTypesDerivedFrom() .Where(type => !type.IsAbstract) .Where(type => !type.IsDefined(typeof(NoInjectAttribute), false)) .ToArray(); #else _injectableTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => assembly.GetTypes()) .Where(type => typeof(T).IsAssignableFrom(type)) .Where(type => !type.IsAbstract) .Where(type => !type.IsDefined(typeof(NoInjectAttribute), false)) .ToArray(); #endif } return _injectableTypes; } /// /// Creates instances for all of the injectable types available. /// /// Forces a reload of the types instead of using the cache. /// The injectable instances. public IEnumerable GetInjectedInstances(bool forceReload = false) { IEnumerable injectableTypes = GetInjectableTypes(forceReload); return GetInjectedInstances(injectableTypes); } /// /// Creates instances from a custom sequence of injectable types. /// /// The types to create instances for. /// The injectable instances. public IEnumerable GetInjectedInstances(IEnumerable injectableTypes) { foreach (Type type in injectableTypes) { T instance = default; bool success = false; try { instance = (T)Activator.CreateInstance(type); success = true; } catch (MissingMethodException) { Debug.LogError($"Could not load {typeof(T)} {type} as it is missing a public parameterless constructor."); } catch (Exception e) { Debug.LogException(e); } if (success) { yield return instance; } } } } }