private static IEnumerable ResolveMany(Type t, ResolutionPackage resolutionPackage) { foreach (Registration match in ResolveType(t)) { foreach (object instance in Resolve(match, resolutionPackage)) { yield return(instance); } } }
/// <summary> /// Creates an instance of the engine and copies the providers from the resolution package /// </summary> public Engine(ResolutionPackage resolutionPackage) { if (resolutionPackage is null) { throw new ArgumentNullException(nameof(resolutionPackage)); } foreach (KeyValuePair <Type, AbstractServiceProvider> provider in resolutionPackage.ServiceProviders) { this.AllProviders.Add(provider.Key, provider.Value); } }
internal static object CreateRegisteredInstance(Registration registration, ResolutionPackage resolutionPackage, bool optional = false) { object toReturn = null; if (registration.InjectionFactory != null) { toReturn = registration.InjectionFactory.Invoke(Resolve <IServiceProvider>(resolutionPackage) ?? new Engine(resolutionPackage)); } else if (registration.ToInstantiate != null && (!registration.ToInstantiate.IsInterface && !registration.ToInstantiate.IsAbstract)) { toReturn = InstantiateObject(registration, resolutionPackage, optional); } if (toReturn != null) { ResolveProperties(toReturn, resolutionPackage); } return(toReturn); }
internal static bool IsResolvable(Type t, ResolutionPackage resolutionPackage) { if (ResolvableTypes.TryGetValue(t, out bool toReturn)) { return(toReturn); } if (resolutionPackage.ResolutionPackageServices.ContainsKey(t)) { return(true); } bool alreadyResolvable = IsValidIEnumerable(t) || ResolveType(t).Any(); if (!alreadyResolvable) { if (typeof(ISelfRegistering).IsAssignableFrom(t)) { if (typeof(IRegisterMostDerived).IsAssignableFrom(t)) { Type toRegister = TypeFactory.GetMostDerivedType(t); RegisterAllBaseTypes(t, toRegister, typeof(TransientServiceProvider)); } else { Register(t, t, typeof(TransientServiceProvider)); } toReturn = true; } } else { toReturn = true; } ResolvableTypes.TryAdd(t, toReturn); return(toReturn); }
private static object Resolve(Type t, ResolutionPackage resolutionPackage, bool optional = false) { if (t is null) { return(null); } if (IsValidIEnumerable(t, out Type collectionType)) { IList toReturn = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(collectionType)); foreach (object thisItem in ResolveMany(t, resolutionPackage)) { toReturn.Add(thisItem); } return(toReturn); } else { return(ResolveSingle(t, resolutionPackage, optional)); } }
/// <summary> /// Resolves child properties of an object through the engine /// </summary> /// <typeparam name="T">Any class</typeparam> /// <param name="o">The object to resolve the properties of</param> /// <param name="resolutionPackage">Information to be used when resolving types</param> /// <returns>The passed in object with resolved properties (just in case)</returns> public static T ResolveProperties <T>(T o, ResolutionPackage resolutionPackage) { if (resolutionPackage is null) { throw new ArgumentNullException(nameof(resolutionPackage)); } Type oType = o.GetType(); if (!ChildDependencies.ContainsKey(oType)) { ChildDependencies.TryAdd(oType, oType.GetProperties().Where(p => Attribute.IsDefined(p, typeof(DependencyAttribute))).ToList()); } foreach (PropertyInfo thisDependency in ChildDependencies[oType]) { if (!AnyRegistration(thisDependency.PropertyType)) { Type defaultType = thisDependency.GetCustomAttribute <DependencyAttribute>().Default; thisDependency.SetValue(o, Resolve( new Registration() { ServiceProvider = typeof(TransientServiceProvider), RegisteredType = thisDependency.PropertyType, ToInstantiate = defaultType ?? thisDependency.PropertyType }, resolutionPackage).SingleOrDefault()); } else { thisDependency.SetValue(o, Resolve(thisDependency.PropertyType, resolutionPackage, true)); } } return(o); }
private static IEnumerable <object> Resolve(Registration match, ResolutionPackage resolutionPackage, bool optional = false) { resolutionPackage.AddStack(match); //We resolve with that registration. Or attempt to if (!resolutionPackage.ServiceProviders.TryGetValue(match.ServiceProvider, out AbstractServiceProvider thisManager)) { if (!resolutionPackage.ServiceProviders.TryGetValue(typeof(TransientServiceProvider), out thisManager)) { throw new Exception($"Type {match.ToInstantiate} could not be created because service provider of type {match.ServiceProvider} was not found in the current registrations and a transient service provider could not be found"); } else { StaticLogger.Log($"Type {match.ToInstantiate} created using transient service provider because {match.ServiceProvider} was not found in the current registrations", StaticLogger.LoggingLevel.Call); } } //If no registration was found, or there was no instance existing if (!(thisManager.GetService(match.ToInstantiate) is IList <object> toReturn) || !toReturn.Any()) { //Create an instance toReturn = new List <object>(); object o = CreateRegisteredInstance(match, resolutionPackage, optional); if (o != null) { thisManager?.Add(match.ToInstantiate, o); toReturn.Add(o); } } resolutionPackage.RemoveStack(); return(toReturn); }
internal static object InstantiateObject(Registration registration, ResolutionPackage resolutionPackage, bool optional = false) { ConstructorInfo[] Constructors = registration.ToInstantiate.GetConstructors(); foreach (ConstructorInfo thisConstructor in Constructors.OrderByDescending(c => c.GetParameters().Length)) { ParameterInfo[] Parameters = thisConstructor.GetParameters(); bool IsMatch = true; foreach (ParameterInfo thisParameter in Parameters) { if (!IsResolvable(thisParameter.ParameterType, resolutionPackage) && !thisParameter.IsOptional) { IsMatch = false; break; } } if (IsMatch) { object[] Params = Parameters.Select(p => Resolve(p.ParameterType, resolutionPackage)).ToArray(); return(Activator.CreateInstance(registration.ToInstantiate, Params)); } } if (!optional) { StringBuilder registered = new StringBuilder(); foreach (KeyValuePair <Type, ConcurrentList <Registration> > r in Engine.Registrations) { registered.Append(r.Key.Name + System.Environment.NewLine); foreach (Registration thisRegistration in r.Value) { registered.Append($"\t{thisRegistration.RegisteredType.FullName} => {thisRegistration.ToInstantiate.FullName} as {thisRegistration.ServiceProvider.FullName}"); } } MissingInjectableConstructorException exception = new MissingInjectableConstructorException(registration.ToInstantiate); string DebugText = registered.ToString(); string Error = $"Type ({registration.ToInstantiate.FullName}) does not contain constructor with registered parameters..."; foreach (ConstructorInfo constructor in Constructors) { FailingConstructor failingConstructor = new FailingConstructor { Constructor = constructor, MissingParameters = constructor.GetParameters().Where(t => !IsRegistered(t.ParameterType)).ToArray() }; Error += System.Environment.NewLine + string.Join(", ", constructor.GetParameters().Select(s => $"{s.ParameterType.FullName} {s.Name}")); Error += System.Environment.NewLine + "Missing registrations: " + string.Join(", ", failingConstructor.MissingParameters.Select(s => $"{s.ParameterType.FullName} {s.Name}")); } exception.SetMessage(Error); throw exception; } else { return(null); } }
private static T Resolve <T>(ResolutionPackage resolutionPackage) where T : class { return(Resolve(typeof(T), resolutionPackage) as T); }
/// <summary> /// Returns a single instance of the type based on the LAST registration /// </summary> /// <param name="t">The type to return</param> /// <param name="resolutionPackage">A resolution package containing any providers</param> /// <param name="optional">Dont throw an error if its null</param> /// <returns>An instance of the requested type, if registered</returns> private static object ResolveSingle(Type t, ResolutionPackage resolutionPackage, bool optional = false) { if (!IsResolvable(t, resolutionPackage)) { return(null); } if (resolutionPackage.ResolutionPackageServices.ContainsKey(t)) { return(resolutionPackage.ResolutionPackageServices[t]); } //This whole IF block attempts to find a dependency consolidator for the requested type, and if its found it squishes all the registered instances into it //Which effectively allows for a class that converts an IEnumerable of a registered type into a single instance, which is great for things like providers //that may be registered independently but can be treated as a single unit through a consolidating class, that way everywhere the dependency is resolved //doesn't need to accept an IEnumerable of the types if (DependencyConsolidators.TryGetValue(t, out Type consolidatorType)) { if (resolutionPackage.DependencyConsolidators.TryGetValue(t, out object consolidatedObject)) { return(consolidatedObject); } object consolidator; foreach (Registration reg in ResolveType(consolidatorType)) { if (!resolutionPackage.ServiceProviders.TryGetValue(reg.ServiceProvider, out AbstractServiceProvider provider)) { provider = Activator.CreateInstance(reg.ServiceProvider) as AbstractServiceProvider; resolutionPackage.ServiceProviders.Add(reg.ServiceProvider, provider); } consolidator = (provider.GetService(consolidatorType) as IList <object>)?.SingleOrDefault(); if (consolidator != null) { return(consolidator); } } try { consolidator = Activator.CreateInstance(consolidatorType); } catch (Exception ex) { throw new Exception($"An error occured or creating and instance of the dependency consolidator type {consolidatorType}", ex); } IDeferredResolutionCollection deferredResolutionCollection = Activator.CreateInstance(typeof(DeferredResolutionCollection <>).MakeGenericType(t)) as IDeferredResolutionCollection; foreach (Registration reg in ResolveType(t)) { if (reg.ToInstantiate != consolidatorType) { deferredResolutionCollection.Add(() => Resolve(reg, resolutionPackage, optional).LastOrDefault()); } } MethodInfo setMethod = typeof(IConsolidateDependencies <>).MakeGenericType(t).GetMethod(nameof(IConsolidateDependencies <object> .Consolidate)); consolidatedObject = setMethod.Invoke(consolidator, new object[] { deferredResolutionCollection }); resolutionPackage.DependencyConsolidators.Add(t, consolidatedObject); foreach (Registration reg in ResolveType(consolidatorType)) { resolutionPackage.ServiceProviders[reg.ServiceProvider].Add(consolidatorType, consolidator); } return(consolidatedObject); } else { foreach (Registration reg in ResolveType(t)) { object toReturn = Resolve(reg, resolutionPackage, optional).LastOrDefault(); if (toReturn != null) { return(toReturn); } } } return(null); }