/// <summary> /// Ensure no component of the given type is registered yet /// </summary> /// <param name="type">The type of the component</param> private void EnsureNotRegistered(Type type) { // Ensure the type was not already registered if (Registrations.ContainsKey(type)) { throw ComponentResolutionException.AlreadyRegistered(type); } }
/// <summary> /// Internal method for getting a type by specifying and existing set of pending resolutions, mainly used /// to detect circular dependencies /// </summary> /// <param name="type">The type of the component</param> /// <param name="pendingResolutions">A set of pending resolutions</param> /// <param name="parameters">The parameters to inject manually</param> /// <returns>The component of the requested type</returns> private object GetInternal(Type type, IDictionary <Type, ComponentRegistration> pendingResolutions, Hashtable parameters) { // Get the registration for the given type ComponentRegistration registration; // Ensure the component is registered if (!Registrations.TryGetValue(type, out registration)) { throw ComponentResolutionException.NotRegistered(type); } // Try and retrieve the instance as a singleton instance when appropriate if (registration.Singleton) { object singleton; if (Singletons.TryGetValue(type, out singleton)) { return(singleton); } } object instance; if (registration.Instance != null) { // Use the instance if provided instance = registration.Instance; } else if (registration.FactoryMethod != null) { // Use the factory method provided instance = registration.FactoryMethod(); } else { // Find the constructor for the given type var ctor = GetConstructor(registration.Type); // Ensure there is an eligible constructor if (ctor == null) { throw ComponentResolutionException.ConstructorNotFound(type); } var dependencies = ctor.GetParameters().ToList(); // Create a dictionary of seen type that are not yet resolved pendingResolutions = pendingResolutions ?? new Dictionary <Type, ComponentRegistration>(); // Add an entry for the current type in the pending resolutions pendingResolutions.Add(type, registration); // The list of resolved dependencies var resolvedDependencies = new object[dependencies.Count]; var currentDependencyIndex = 0; // For every dependency foreach (var dependency in dependencies) { // Try and get the parameter from the manual parameter list if (parameters != null) { var argument = parameters[dependency.Name]; if (argument != null && dependency.ParameterType.IsAssignableFrom(argument.GetType())) { resolvedDependencies[currentDependencyIndex++] = argument; continue; } } // Try and get the parameter from the default parameter list if (registration.Parameters != null) { var argument = registration.Parameters[dependency.Name]; if (argument != null && dependency.ParameterType.IsAssignableFrom(argument.GetType())) { resolvedDependencies[currentDependencyIndex++] = argument; continue; } } // The dependency could not be resolved with manually provided parameters. // Resolve it using other components registered var dependencyType = dependency.ParameterType; // Ensure there is no circular dependency if (pendingResolutions.ContainsKey(dependencyType)) { throw ComponentResolutionException.CircularDependency(type, dependencyType); } try { // Create an instance of the dependency recursively resolvedDependencies[currentDependencyIndex++] = GetInternal(dependencyType, pendingResolutions, null); } catch (ComponentResolutionException ex) { // Wrap an throw the exception throw ComponentResolutionException.DependencyResolution(type, ex); } } // Create an instance of the type using the constructor obtained before instance = ctor.Invoke(resolvedDependencies); } // Register the instance as a singleton when appropriate if (registration.Singleton) { Singletons.Add(type, instance); } // Return the newly created instance return(instance); }