private ConstructorExpression BuildConstructorExpression(Type concreteType, DependencyChain chain) { // If the concrete type is a generic type definition, we cannot invoke it's constructor. // We need to construct the type using the generic arguments defined on the requested type from the dependency chain. if (concreteType.IsGenericTypeDefinition) { concreteType = concreteType.MakeGenericType(chain.Type.GetGenericArguments()); } // Order by constructors with the most amount of parameters. var constructors = concreteType.GetConstructors(); var expression = new ConstructorExpression(); // Don't bother ordering if only 1 constructor is present. if (constructors.Length == 1) { return(BuildConstructor(constructors[0], chain)); } var constructor = constructors .OrderByDescending(x => x.GetParameters().Length) .FirstOrDefault(); // No valid public constructors were found. if (constructor == null) { throw new MissingConstructorException(concreteType); } return(BuildConstructor(constructor, chain)); }
internal IEnumerable <object> GetServices(DependencyChain chain, ContainerScope scope) { // First, read the registration from the runtime to determine the lifespan. var registrations = _registrationSource.GetRegistrations(chain.Type); return(registrations.Select(registration => { switch (registration.ServiceLifespan) { case ServiceLifespan.Transient: // For Transient, activate a new instance each time. return _backend.ActivateInstance(registration, chain, new ServiceVisitor(this, scope)); case ServiceLifespan.Singleton: // For Singleton, rely on the runtime scope to retrieve the instance. return _runtimeScope.GetScopedService(registration, chain); case ServiceLifespan.Scoped: // For Scoped, rely on the scope to retrieve the instance. return scope.GetScopedService(registration, chain); default: throw new NotImplementedException($"Lifespan '{registration.ServiceLifespan}' is not supported"); } })); }
// We produce the resolution stack by recursively interating through the dependency chain nodes. private string[] GetResolutionStack(DependencyChain chain) { var resolutionStack = new List <string> { chain.Type.FullName }; // Attempt to get the resultion stack of the parent node and append it to the current stack. if (chain.Parent != null) { var parentStack = GetResolutionStack(chain.Parent); resolutionStack.AddRange(parentStack); } return(resolutionStack.ToArray()); }
private bool CheckDependency(DependencyChain chain, HashSet <Type> types) { // If the list of types contains the current type in the dependency, we have a circular reference. if (types.Contains(chain.Type)) { return(true); } types.Add(chain.Type); // If the chain node has a parent, check the parent type. if (chain.Parent != null) { return(CheckDependency(chain.Parent, types)); } // We've reached the top node, no circular reference found. return(false); }
public virtual object ActivateInstance(ServiceRegistration registration, DependencyChain chain, IContainerVisitor visitor) { // Check dependency chain to see if we have a circular dependency. if (DetectCycle(chain)) { throw new CircularDependencyException(chain.Type, GetResolutionStack(chain)); } // If a factory method is defined, invoke it to activate the service. if (registration.FactoryMethod != null) { return(visitor.InvokeServiceFactory(registration.FactoryMethod)); } // Check the cache to see if the constructor expression was previously built. if (!_constructorCache.TryGetValue(registration.ServiceType, out var expression)) { // Constructor expression hasn't been cached, we need to build it. expression = BuildConstructorExpression(registration.ConcreteType, chain); _constructorCache.Add(registration.ServiceType, expression); } var parameters = new object[expression.ParameterChains.Length]; for (var i = 0; i < expression.ParameterChains.Length; i++) { var paramChain = expression.ParameterChains[i]; // Attempt to locate the services for the parameter. var services = visitor.LocateServices(paramChain); // Create the parameter from the resolved services. var parameter = CreateService(paramChain.Type, services); parameters[i] = parameter ?? throw new MissingDependencyException(paramChain.Type, chain.Type, GetResolutionStack(paramChain)); } return(expression.Activate(parameters)); }
private ConstructorExpression BuildConstructor(ConstructorInfo constructor, DependencyChain chain) { var parameters = constructor.GetParameters(); var expression = new ConstructorExpression { ParameterChains = new DependencyChain[parameters.Length] }; // Iterate through all the parameters in the constructor. for (var i = 0; i < parameters.Length; i++) { // Create a new DependencyChain node for the parameter type. var childChain = new DependencyChain(parameters[i].ParameterType, chain); expression.ParameterChains[i] = childChain; } expression.BuildExpression(constructor); return(expression); }
internal object GetScopedService(ServiceRegistration registration, DependencyChain chain) { if (_disposed) { throw new ObjectDisposedException(nameof(IContainerScope)); } // Attempt to retrieve the instance from the service context. var instance = _scopeContext.GetService(registration.ConcreteType); // If instance doesn't exist, we need to activate it. if (instance == null) { // Use instance on registration, if defined. // Otherwise, activate a new instance. instance = registration.ServiceInstance ?? _backend.ActivateInstance(registration, chain, new ServiceVisitor(_runtime, this)); _scopeContext.AddService(registration.ConcreteType, instance); } return(instance); }
public IEnumerable <object> LocateServices(DependencyChain chain) { chain = chain ?? throw new ArgumentNullException(nameof(chain)); return(_runtime.GetServices(chain, _scope)); }
// We attempt to detect a circular dependency by recursively interating through the types in the chain. private bool DetectCycle(DependencyChain chain) { var types = new HashSet <Type>(); return(CheckDependency(chain, types)); }