/// <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); } } }