/// <summary>
        /// Resolve all injectable methods across the type-chain.
        /// </summary>
        /// <param name="objToInject">The object for which to inject its methods.</param>
        /// <param name="currentType">The current type across the type chain.</param>
        /// <param name="container">The resource container.</param>
        /// <param name="injectionId">An identifier to restrict to specifically defined scopes.</param>
        private static void ResolveMethodDependencies(object objToInject, Type currentType, IReadOnlyDependencyContainer container, string injectionId = null)
        {
            if (TryGetTypeInjectionInfo(currentType, out TypeInjectionCache cache))
            {
                bool isStaticInjection = objToInject is Type;

                foreach (MemberInjectionValue <MethodInfo> method in cache.InjectableMethods)
                {
                    if (method.Attribute.IsInjectionIdDefined(injectionId))
                    {
                        if (isStaticInjection && method.Member.IsStatic)
                        {
                            ParameterInfo[] parameterInfo = method.Member.GetParameters();
                            object[]        parameters    = TypeReflectionUtilities.GetParameterInvokationList(parameterInfo.Length);
                            FillPamaterInjectionList(parameterInfo, parameters, container);
                            method.Member.Invoke(null, parameters);
                            TypeReflectionUtilities.ReturnParameterInvokationList(parameters);
                        }
                        else if (!isStaticInjection && !method.Member.IsStatic)
                        {
                            ParameterInfo[] parameterInfo = method.Member.GetParameters();
                            object[]        parameters    = TypeReflectionUtilities.GetParameterInvokationList(parameterInfo.Length);
                            FillPamaterInjectionList(parameterInfo, parameters, container);
                            method.Member.Invoke(objToInject, parameters);
                            TypeReflectionUtilities.ReturnParameterInvokationList(parameters);
                        }
                    }
                }
            }
        }
        /// <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>
        /// Invoke any methods found on the target object that have been marked as being response callbacks.
        /// The method can define parameters in any order refering to the handle, request and/or response.
        /// The message handle's request is required to assigned. The response may be null.
        /// </summary>
        /// <param name="target">The object on which to invoke response callback methods</param>
        /// <param name="handle">The handle which contains the request and response values.</param>
        /// <typeparam name="TCallbackAttr">The attribute to look on any of the target's methods.</typeparam>
        /// <typeparam name="TResponseAssocAttr">The attribute that's used to associate a request type with a response type.</typeparam>
        public static void InvokeResponseCallback <TCallbackAttr, TResponseAssocAttr>(object target, IWeblinkMessageHandle handle)
            where TCallbackAttr : WeblinkResponseCallbackAttribute
            where TResponseAssocAttr : WeblinkResponseAttribute
        {
            target.ThrowIfNull(nameof(target));
            handle.ThrowIfNull(nameof(handle));
            handle.ThrowIfNull(nameof(handle.Request));

            Type requestType = handle.Request.GetType();

            if (!IsResponseTypeDefined <TResponseAssocAttr>(requestType))
            {
                return;
            }

            Type handleType   = handle.GetType();
            Type targetType   = target.GetType();
            Type responseType = GetResponseType <TResponseAssocAttr>(requestType);

            IWeblinkReflectionMap reflectionMap = GetWeblinkReflectionMap(targetType);

            foreach (ITargetedCallback callback in reflectionMap.GetTargetedCallbacks(typeof(TCallbackAttr)))
            {
                if (!callback.ResponseType.IsAssignableFrom(responseType))
                {
                    continue;
                }

                if (!callback.Parameters.IsNullOrEmpty())
                {
                    object[] parameters = TypeReflectionUtilities.GetParameterInvokationList(callback.Parameters.Length);
                    for (int i = 0; i < parameters.Length; ++i)
                    {
                        Type parameterType = callback.Parameters[i].ParameterType;
                        if (parameterType.IsAssignableFrom(handleType))
                        {
                            parameters[i] = handle;
                        }
                        else if (parameterType.IsAssignableFrom(requestType))
                        {
                            parameters[i] = handle.Request;
                        }
                        else if (parameterType.IsAssignableFrom(responseType))
                        {
                            parameters[i] = handle.Response;
                        }
                        else
                        {
                            parameters[i] = null;
                        }
                    }

                    callback.Method.Invoke(target, parameters);
                    TypeReflectionUtilities.ReturnParameterInvokationList(parameters);
                }
                else
                {
                    callback.Method.Invoke(target, null);
                }
            }
        }