/// <summary>
 /// Inject the component with named resources found in the dependency container.
 /// Only resources marked with a matching name will get injected.
 /// </summary>
 /// <param name="component">Component to be injected.</param>
 /// <param name="container">Container containing resources that can be injected.</param>
 /// <param name="injectionId">Name of the scope these resources belong to.</param>
 public static void Inject(this MonoBehaviour component, IReadOnlyDependencyContainer container, string injectionId)
 {
     component.ThrowIfNull(nameof(component));
     container.ThrowIfNull(nameof(container));
     injectionId.ThrowIfNullOrEmpty(nameof(injectionId));
     DependencyInjector.Inject(container, injectionId, component);
 }
        /// <summary>
        /// Inject the target object using the bindings found in the container.
        /// Note: if the target is of type Type, then it's static members will be injected.
        /// </summary>
        /// <param name="container">Container with dependency bindings.</param>
        /// <param name="target">Target to be injected.</param>
        public static void Inject(IReadOnlyDependencyContainer container, object target)
        {
            container.ThrowIfNull(nameof(container));
            target.ThrowIfNull(nameof(target));

            ResolveDependenciesForObject(target, container);
        }
        /// <summary>
        /// Creates an instance of the target type and injects the newly create object.
        /// Note: a suitable constructor is necessary to create the instance. Either a constructor marked
        /// with the 'Inject' attribute (with matching injection identifier), or an accessable default constructor.
        /// </summary>
        /// <param name="targetType">The type of object to create an instance of.</param>
        /// <param name="container">Container with resources to inject.</param>
        /// <param name="injectionId">Only injects members with the same injection identifier.</param>
        /// <returns>An instance of the target type, injected with resources found in the container.</returns>
        public static object CreateAndInject(Type targetType, IReadOnlyDependencyContainer container, string injectionId)
        {
            targetType.ThrowIfNull(nameof(targetType));
            container.ThrowIfNull(nameof(container));

            if (targetType.IsInterface || targetType.IsAbstract)
            {
                throw new DependencyInjectionException("Cannot create an instance of type {0} because it is either an interface or declared abstract.", targetType.Name);
            }

            object instance = null;

            if (TryGetTypeInjectionInfo(targetType, out TypeInjectionCache typeInfo) && typeInfo.InjectableConstructors.Any(c => c.Attribute.IsInjectionIdDefined(string.Empty)))
            {
                MemberInjectionValue <ConstructorInfo> constructorInfo = typeInfo.InjectableConstructors.First(c => c.Attribute.IsInjectionIdDefined(string.Empty));
                ParameterInfo[] parameterInfo = constructorInfo.Member.GetParameters();
                object[]        parameters    = TypeReflectionUtilities.GetParameterInvokationList(parameterInfo.Length);
                FillPamaterInjectionList(parameterInfo, parameters, container);
                instance = constructorInfo.Member.Invoke(parameters);
                TypeReflectionUtilities.ReturnParameterInvokationList(parameters);
            }
            else
            {
                instance = Activator.CreateInstance(targetType, false);
            }

            // Inject the instance as well for fields, properties and other methods.
            Inject(container, instance);
            return(instance);
        }
        /// <summary>
        /// Inject the components found on the GameObject. Optionally includes the children as well.
        /// </summary>
        /// <param name="gameObject">The GameObject of which the components will be injected.</param>
        /// <param name="container">Container containing resources that can be injected.</param>
        /// <param name="includeChildren">Include components found in children of the GameObject.</param>
        public static void Inject(this GameObject gameObject, IReadOnlyDependencyContainer container, bool includeChildren = false)
        {
            gameObject.ThrowIfNull(nameof(gameObject));
            container.ThrowIfNull(nameof(container));
            IEnumerable <MonoBehaviour> components = includeChildren ? gameObject.GetComponentsInChildren <MonoBehaviour>(true) : gameObject.GetComponents <MonoBehaviour>();

            DependencyInjector.Inject(container, components);
        }
        /// <summary>
        /// Inject the target object using the bindings found in the container.
        /// Note: if the target is of type Type, then it's static members will be injected.
        /// </summary>
        /// <param name="container">Container with dependency bindings.</param>
        /// <param name="injectionId">Only injects members with the injection ID.</param>
        /// <param name="target">Target to be injected.</param>
        public static void Inject(IReadOnlyDependencyContainer container, string injectionId, object target)
        {
            container.ThrowIfNull(nameof(container));
            injectionId.ThrowIfNullOrWhitespace(nameof(injectionId));
            target.ThrowIfNull(nameof(target));

            ResolveDependenciesForObject(target, container, injectionId);
        }
        /// <summary>
        /// Adds a component of the desired type to the game object and injects it with
        /// the resources found in the container, under the given injection identifier.
        /// </summary>
        /// <param name="gameObject">The game object to add the component to.</param>
        /// <param name="container">Container containing resources that can be injected.</param>
        /// <param name="injectionId">Name of the scope these resources belong to.</param>
        /// <typeparam name="TComponent">Type of component to tadd to the game object.</typeparam>
        /// <returns>The component, injected with resources.</returns>
        public static TComponent AddComponentAndInject <TComponent>(this GameObject gameObject, IReadOnlyDependencyContainer container, string injectionId)
            where TComponent : MonoBehaviour
        {
            gameObject.ThrowIfNull(nameof(gameObject));
            container.ThrowIfNull(nameof(container));

            TComponent c = gameObject.AddComponent <TComponent>();

            c.Inject(container, injectionId);

            return(c);
        }
        /// <summary>
        /// Inject the target objects using the bindings found in the container.
        /// </summary>
        /// <param name="container">Container with dependency bindings.</param>
        /// <param name="targets">Targets to be injected.</param>
        public static void Inject(IReadOnlyDependencyContainer container, IEnumerable targets)
        {
            container.ThrowIfNull(nameof(container));
            targets.ThrowIfNull(nameof(targets));

            foreach (object target in targets)
            {
                if (target != null)
                {
                    ResolveDependenciesForObject(target, container);
                }
            }
        }
        /// <summary>
        /// Inject the target objects using the bindings found in the container.
        /// </summary>
        /// <param name="container">Container with dependency bindings.</param>
        /// <param name="injectionId">Only injects members with the injection ID.</param>
        /// <param name="targets">Targets to be injected.</param>
        public static void Inject(IReadOnlyDependencyContainer container, string injectionId, IEnumerable targets)
        {
            container.ThrowIfNull(nameof(container));
            injectionId.ThrowIfNullOrWhitespace(nameof(injectionId));
            targets.ThrowIfNull(nameof(targets));

            foreach (object target in targets)
            {
                if (target != null)
                {
                    ResolveDependenciesForObject(target, container, injectionId);
                }
            }
        }
 /// <summary>
 /// Inject the component with the resources found in the dependency container.
 /// </summary>
 /// <param name="component">Component to be injected</param>
 /// <param name="container">Container containing resources that can be injected.</param>
 public static void Inject(this MonoBehaviour component, IReadOnlyDependencyContainer container)
 {
     component.ThrowIfNull(nameof(component));
     container.ThrowIfNull(nameof(container));
     DependencyInjector.Inject(container, component);
 }
 /// <summary>
 /// Inject the entire colletion of components with the resources found in the dependency container.
 /// </summary>
 /// <param name="components">Components to be injected.</param>
 /// <param name="container">Container containing resources that can be injected.</param>
 public static void Inject(this IEnumerable <MonoBehaviour> components, IReadOnlyDependencyContainer container)
 {
     components.ThrowIfNull(nameof(components));
     container.ThrowIfNull(nameof(container));
     DependencyInjector.Inject(container, components);
 }