public void AddsTypeRequestInfosWithValueTypes() { var typeArray = CreateArrayWithOnlyValueTypes(); var path = new TypeRequestPath(typeArray); for (int i = 0; i < typeArray.Length; i++) { Assert.AreEqual(typeArray[i], path.AllTypes[i]); } Assert.AreEqual(typeArray[0], path.FirstType); Assert.AreEqual(typeArray[typeArray.Length - 1], path.LastType); }
public void DoesThrowCircularDependencyExceptionForDuplicateTypeIfSpecified() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); ExceptionTester.CallMethodAndExpectException<CircularDependencyException>(() => path.PushType(new TypeRequestInfo(typeof(X)), true)); }
public void ReturnsFalseForInvalidPath() { var typeArray = CreateInvalidPath(); var path = new TypeRequestPath(typeArray); Assert.IsFalse(path.IsValid); }
public void ReturnsTrueForValidPath() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); Assert.IsTrue(path.IsValid); }
public void ReturnsRightType() { var typeArray = CreateArrayWithOnlyValueTypes(); var path = new TypeRequestPath(typeArray); Assert.AreEqual(typeArray[typeArray.Length - 1], path.LastType); }
/// <summary> /// Creates an instance of the specified type using dependency injection. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct"/> is <c>null</c>.</exception> public object CreateInstance(Type typeToConstruct) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { TypeRequestInfo typeRequestInfo = null; try { typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: TypeRequestPathName); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, new object[] { }); if (_constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = _constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, cachedConstructor, false); if (instanceCreatedWithInjection != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); _constructorCache.Remove(constructorCacheKey); } Log.Debug("Creating instance of type '{0}'. No constructor found in the cache, so searching for the right one.", typeToConstruct.FullName); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructors = typeConstructorsMetadata.GetConstructors(); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, constructor, i < constructors.Count - 1); if (instanceCreatedWithInjection != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); // We found a constructor that works, cache it _constructorCache[constructorCacheKey] = constructor; return(instanceCreatedWithInjection); } } var createdInstanceUsingActivator = CreateInstanceUsingActivator(typeToConstruct); if (createdInstanceUsingActivator != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); return(createdInstanceUsingActivator); } } catch (CircularDependencyException) { throw; } catch (Exception ex) { CloseCurrentTypeIfRequired(typeRequestInfo); Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } CloseCurrentTypeIfRequired(typeRequestInfo); return(null); } }
public void RemovesTypeRangeUntilSpecificType() { var path = new TypeRequestPath(new TypeRequestInfo(typeof(X))); path.PushType(new TypeRequestInfo(typeof(object)), false); path.PushType(new TypeRequestInfo(typeof(Y)), false); path.PushType(new TypeRequestInfo(typeof(object)), false); path.PushType(new TypeRequestInfo(typeof(Z)), false); path.MarkTypeAsNotCreated(new TypeRequestInfo(typeof(Y))); Assert.AreEqual(2, path.TypeCount); Assert.AreEqual(new TypeRequestInfo(typeof(X)), path.AllTypes[0]); Assert.AreEqual(new TypeRequestInfo(typeof(object)), path.AllTypes[1]); }
public void ThrowsInvalidOperationExceptionWhenTypeRequestPathOnlyContainsOneType() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); while (path.AllTypes.Length > 1) { path.PopType(); } ExceptionTester.CallMethodAndExpectException<InvalidOperationException>(path.PopType); }
/// <summary> /// Creates an instance of the specified type using the specified parameters as injection values. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <param name="parameters">The parameters to inject.</param> /// <param name="autoCompleteDependencies">if set to <c>true</c>, the additional dependencies will be auto completed.</param> /// <param name="preventCircularDependencies">if set to <c>true</c>, prevent circular dependencies using the <see cref="TypeRequestPath"/>.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct" /> is <c>null</c>.</exception> private object CreateInstanceWithSpecifiedParameters(Type typeToConstruct, object[] parameters, bool autoCompleteDependencies, bool preventCircularDependencies = true) { Argument.IsNotNull("typeToConstruct", typeToConstruct); if (parameters == null) { parameters = new object[] { }; } lock (_serviceLocator) { TypeRequestInfo typeRequestInfo = null; try { if (preventCircularDependencies) { typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: TypeRequestPathName); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } } var constructorCache = GetConstructorCache(autoCompleteDependencies); var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, parameters); if (constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, cachedConstructor, parameters, false, false); if (instanceCreatedWithInjection != null) { if (preventCircularDependencies) { CompleteTypeRequestPathIfRequired(typeRequestInfo); } return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); constructorCache.Remove(constructorCacheKey); } Log.Debug("Creating instance of type '{0}' using specific parameters. No constructor found in the cache, so searching for the right one", typeToConstruct.FullName); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructors = typeConstructorsMetadata.GetConstructors(parameters.Count(), !autoCompleteDependencies); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, constructor, parameters, true, i < constructors.Count - 1); if (instanceCreatedWithInjection != null) { if (preventCircularDependencies) { CompleteTypeRequestPathIfRequired(typeRequestInfo); } // We found a constructor that works, cache it constructorCache[constructorCacheKey] = constructor; // Only update the rule when using a constructor for the first time, not when using it from the cache ApiCop.UpdateRule <TooManyDependenciesApiCopRule>("TypeFactory.LimitDependencyInjection", x => x.SetNumberOfDependenciesInjected(typeToConstruct, constructor.GetParameters().Count())); return(instanceCreatedWithInjection); } } Log.Debug("No constructor could be used, cannot construct type '{0}' with the specified parameters", typeToConstruct.FullName); } catch (CircularDependencyException) { throw; } catch (Exception ex) { if (preventCircularDependencies) { CloseCurrentTypeIfRequired(typeRequestInfo); } Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } if (preventCircularDependencies) { CloseCurrentTypeIfRequired(typeRequestInfo); } return(null); } }
/// <summary> /// Creates an instance of the specified type using the specified parameters as injection values. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <param name="parameters">The parameters to inject.</param> /// <param name="autoCompleteDependencies">if set to <c>true</c>, the additional dependencies will be auto completed.</param> /// <param name="preventCircularDependencies">if set to <c>true</c>, prevent circular dependencies using the <see cref="TypeRequestPath"/>.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct" /> is <c>null</c>.</exception> private object CreateInstanceWithSpecifiedParameters(Type typeToConstruct, object[] parameters, bool autoCompleteDependencies, bool preventCircularDependencies = true) { Argument.IsNotNull("typeToConstruct", typeToConstruct); if (parameters == null) { parameters = new object[] { }; } lock (_serviceLocator) { TypeRequestInfo typeRequestInfo = null; try { if (preventCircularDependencies) { typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: TypeRequestPathName); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } } var constructorCache = GetConstructorCache(autoCompleteDependencies); var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, parameters); if (constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, cachedConstructor, parameters, false, false); if (instanceCreatedWithInjection != null) { if (preventCircularDependencies) { CompleteTypeRequestPathIfRequired(typeRequestInfo); } return instanceCreatedWithInjection; } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); constructorCache.Remove(constructorCacheKey); } Log.Debug("Creating instance of type '{0}' using specific parameters. No constructor found in the cache, so searching for the right one", typeToConstruct.FullName); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructors = typeConstructorsMetadata.GetConstructors(parameters.Count(), !autoCompleteDependencies); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, constructor, parameters, true, i < constructors.Count - 1); if (instanceCreatedWithInjection != null) { if (preventCircularDependencies) { CompleteTypeRequestPathIfRequired(typeRequestInfo); } // We found a constructor that works, cache it constructorCache[constructorCacheKey] = constructor; // Only update the rule when using a constructor for the first time, not when using it from the cache ApiCop.UpdateRule<TooManyDependenciesApiCopRule>("TypeFactory.LimitDependencyInjection", x => x.SetNumberOfDependenciesInjected(typeToConstruct, constructor.GetParameters().Count())); return instanceCreatedWithInjection; } } Log.Debug("No constructor could be used, cannot construct type '{0}' with the specified parameters", typeToConstruct.FullName); } catch (CircularDependencyException) { throw; } catch (Exception ex) { if (preventCircularDependencies) { CloseCurrentTypeIfRequired(typeRequestInfo); } Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } if (preventCircularDependencies) { CloseCurrentTypeIfRequired(typeRequestInfo); } return null; } }
/// <summary> /// Marks the specified type as not being created. If this was the only type being constructed, the type request /// path will be closed. /// </summary> /// <param name="typeRequestInfoForTypeJustConstructed">The type request info for type just constructed.</param> private void CloseCurrentTypeIfRequired(TypeRequestInfo typeRequestInfoForTypeJustConstructed) { lock (_serviceLocator) { if (_currentTypeRequestPath != null) { _currentTypeRequestPath.MarkTypeAsNotCreated(typeRequestInfoForTypeJustConstructed); if (_currentTypeRequestPath.TypeCount == 1) { // We failed to create the only type in the request path, exit _currentTypeRequestPath = null; } } } }
/// <summary> /// Completes the type request path by checking if the currently created type is the same as the first /// type meaning that the type is successfully created and the current type request path can be set to <c>null</c>. /// </summary> /// <param name="typeRequestInfoForTypeJustConstructed">The type request info.</param> private void CompleteTypeRequestPathIfRequired(TypeRequestInfo typeRequestInfoForTypeJustConstructed) { lock (_lockObject) { if (_currentTypeRequestPath != null) { if (_currentTypeRequestPath.FirstType == typeRequestInfoForTypeJustConstructed) { _currentTypeRequestPath = null; } } } }
/// <summary> /// Creates an instance of the specified type using dependency injection. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct"/> is <c>null</c>.</exception> public object CreateInstance(Type typeToConstruct) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { TypeRequestInfo typeRequestInfo = null; try { #if !DISABLE_TYPEPATH typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } #endif if (_constructorCache.ContainsKey(typeToConstruct)) { var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, _constructorCache[typeToConstruct]); if (instanceCreatedWithInjection != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif return instanceCreatedWithInjection; } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); _constructorCache.Remove(typeToConstruct); } Log.Debug("Creating instance of type '{0}'. No constructor found in the cache, so searching for the right one.", typeToConstruct.FullName); var constructors = (from constructor in typeToConstruct.GetConstructorsEx() orderby constructor.GetParameters().Count() descending select constructor).ToList(); foreach (var constructor in constructors) { var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, constructor); if (instanceCreatedWithInjection != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif // We found a constructor that works, cache it _constructorCache[typeToConstruct] = constructor; return instanceCreatedWithInjection; } } var createdInstanceUsingActivator = CreateInstanceUsingActivator(typeToConstruct); if (createdInstanceUsingActivator != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif return createdInstanceUsingActivator; } } catch (CircularDependencyException) { throw; } catch (Exception ex) { CloseCurrentTypeTypeIfRequired(typeRequestInfo); Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } CloseCurrentTypeTypeIfRequired(typeRequestInfo); return null; } }
/// <summary> /// Creates an instance of the specified type using the specified parameters as injection values. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <param name="tag">The preferred tag when resolving dependencies.</param> /// <param name="parameters">The parameters to inject.</param> /// <param name="autoCompleteDependencies">if set to <c>true</c>, the additional dependencies will be auto completed.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct" /> is <c>null</c>.</exception> private object CreateInstanceWithSpecifiedParameters(Type typeToConstruct, object tag, object[] parameters, bool autoCompleteDependencies) { Argument.IsNotNull("typeToConstruct", typeToConstruct); if (parameters is null) { parameters = ArrayShim.Empty <object>(); } var previousRequestPath = _currentTypeRequestPath.Value; try { var typeRequestInfo = new TypeRequestInfo(typeToConstruct); _currentTypeRequestPath.Value = TypeRequestPath.Branch(previousRequestPath, typeRequestInfo); var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, autoCompleteDependencies, parameters); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructorCacheValue = GetConstructor(constructorCacheKey); if (constructorCacheValue.ConstructorInfo != null) { var cachedConstructor = constructorCacheValue.ConstructorInfo; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, cachedConstructor, tag, parameters, false, false, typeConstructorsMetadata); if (instanceCreatedWithInjection != null) { return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); SetConstructor(constructorCacheKey, constructorCacheValue, null); } Log.Debug("Creating instance of type '{0}' using specific parameters. No constructor found in the cache, so searching for the right one", typeToConstruct.FullName); var constructors = typeConstructorsMetadata.GetConstructors(parameters.Length, !autoCompleteDependencies).SortByParametersMatchDistance(parameters).ToList(); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateToConstruct(typeToConstruct, constructor, tag, parameters, true, i < constructors.Count - 1, typeConstructorsMetadata); if (instanceCreatedWithInjection != null) { // We found a constructor that works, cache it SetConstructor(constructorCacheKey, constructorCacheValue, constructor); // Only update the rule when using a constructor for the first time, not when using it from the cache ApiCop.UpdateRule <TooManyDependenciesApiCopRule>("TypeFactory.LimitDependencyInjection", x => x.SetNumberOfDependenciesInjected(typeToConstruct, constructor.GetParameters().Count())); return(instanceCreatedWithInjection); } } Log.Debug("No constructor could be used, cannot construct type '{0}' with the specified parameters", typeToConstruct.FullName); } catch (CircularDependencyException) { throw; } catch (Exception ex) { Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } finally { _currentTypeRequestPath.Value = previousRequestPath; } return(null); }
/// <summary> /// Creates an instance of the specified type using dependency injection. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct"/> is <c>null</c>.</exception> public object CreateInstance(Type typeToConstruct) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { TypeRequestInfo typeRequestInfo = null; try { #if !DISABLE_TYPEPATH typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } #endif if (_constructorCache.ContainsKey(typeToConstruct)) { var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, _constructorCache[typeToConstruct]); if (instanceCreatedWithInjection != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif return(instanceCreatedWithInjection); } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); _constructorCache.Remove(typeToConstruct); } Log.Debug("Creating instance of type '{0}'. No constructor found in the cache, so searching for the right one.", typeToConstruct.FullName); var constructors = (from constructor in typeToConstruct.GetConstructorsEx() orderby constructor.GetParameters().Count() descending select constructor).ToList(); foreach (var constructor in constructors) { var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, constructor); if (instanceCreatedWithInjection != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif // We found a constructor that works, cache it _constructorCache[typeToConstruct] = constructor; return(instanceCreatedWithInjection); } } var createdInstanceUsingActivator = CreateInstanceUsingActivator(typeToConstruct); if (createdInstanceUsingActivator != null) { #if !DISABLE_TYPEPATH CompleteTypeRequestPathIfRequired(typeRequestInfo); #endif return(createdInstanceUsingActivator); } } catch (CircularDependencyException) { throw; } catch (Exception ex) { CloseCurrentTypeTypeIfRequired(typeRequestInfo); Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } CloseCurrentTypeTypeIfRequired(typeRequestInfo); return(null); } }
public void DoesNotThrowCircularDependencyExceptionForDuplicateTypeIfNotSpecified() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); path.PushType(new TypeRequestInfo(typeof(X)), false); Assert.IsFalse(path.IsValid); }
public void DoesNotIgnoreValueTypesIfIgnoreValueTypesIsFalse() { var firstType = new TypeRequestInfo(typeof(X)); var path = new TypeRequestPath(firstType, false); path.PushType(new TypeRequestInfo(typeof(DateTime)), false); Assert.AreEqual(typeof(DateTime), path.LastType.Type); path.PushType(new TypeRequestInfo(typeof(double)), false); Assert.AreEqual(typeof(double), path.LastType.Type); path.PushType(new TypeRequestInfo(typeof(int)), false); Assert.AreEqual(typeof(int), path.LastType.Type); }
/// <summary> /// Resolves the type from a known container. /// </summary> /// <param name="serviceType">Type of the service.</param> /// <param name="tag">The tag to register the service with. The default value is <c>null</c>.</param> /// <returns>An instance of the type registered on the service.</returns> /// <exception cref="ArgumentNullException">The <paramref name="serviceType"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">The type is not found in any container.</exception> private object ResolveTypeFromKnownContainer(Type serviceType, object tag) { Argument.IsNotNull("serviceType", serviceType); lock (this) { var typeRequestInfo = new TypeRequestInfo(serviceType, tag); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: "ServiceLocator"); _currentTypeRequestPath.IgnoreDuplicateRequestsDirectlyAfterEachother = false; } else { _currentTypeRequestPath.PushType(typeRequestInfo, false); if (!_currentTypeRequestPath.IsValid) { // Reset path for next types that are being resolved var typeRequestPath = _currentTypeRequestPath; _currentTypeRequestPath = null; typeRequestPath.ThrowsExceptionIfInvalid(); } } var serviceInfo = new ServiceInfo(serviceType, tag); var registeredTypeInfo = _registeredTypes[serviceInfo]; object instance = registeredTypeInfo.CreateServiceFunc(registeredTypeInfo); if (instance == null) { ThrowTypeNotRegisteredException(serviceType); } if (IsTypeRegisteredAsSingleton(serviceType, tag)) { RegisterInstance(serviceType, instance, tag, this); } CompleteTypeRequestPathIfRequired(typeRequestInfo); return instance; } }
public void ThrowsArgumentNullExceptionForNullTypeRequestInfo() { var typeArray = CreateMixedArray(); var path = new TypeRequestPath(typeArray); ExceptionTester.CallMethodAndExpectException<ArgumentNullException>(() => path.MarkTypeAsNotCreated(null)); }
/// <summary> /// Completes the type request path by checking if the currently created type is the same as the first /// type meaning that the type is successfully created and the current type request path can be set to <c>null</c>. /// </summary> /// <param name="typeRequestInfoForTypeJustConstructed">The type request info.</param> private void CompleteTypeRequestPathIfRequired(TypeRequestInfo typeRequestInfoForTypeJustConstructed) { lock (this) { if (_currentTypeRequestPath != null) { if (_currentTypeRequestPath.LastType == typeRequestInfoForTypeJustConstructed) { _currentTypeRequestPath.MarkTypeAsCreated(typeRequestInfoForTypeJustConstructed); } if (_currentTypeRequestPath.TypeCount == 0) { _currentTypeRequestPath = null; } } } }
/// <summary> /// Throws the <see cref="TypeNotRegisteredException" /> but will also reset the current type request path. /// </summary> /// <param name="type">The type.</param> /// <param name="message">The message.</param> private void ThrowTypeNotRegisteredException(Type type, string message = null) { _currentTypeRequestPath = null; // or _currentTypeRequestPath.PopType(); throw Log.ErrorAndCreateException(msg => new TypeNotRegisteredException(type, msg), "The type '{0}' is not registered", type.GetSafeFullName()); }
/// <summary> /// Creates an instance of the specified type using dependency injection. /// </summary> /// <param name="typeToConstruct">The type to construct.</param> /// <returns>The instantiated type using dependency injection.</returns> /// <exception cref="ArgumentNullException">The <paramref name="typeToConstruct"/> is <c>null</c>.</exception> public object CreateInstance(Type typeToConstruct) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { TypeRequestInfo typeRequestInfo = null; try { typeRequestInfo = new TypeRequestInfo(typeToConstruct); if (_currentTypeRequestPath == null) { _currentTypeRequestPath = new TypeRequestPath(typeRequestInfo, name: TypeRequestPathName); } else { _currentTypeRequestPath.PushType(typeRequestInfo, true); } var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, new object[] { }); if (_constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = _constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, cachedConstructor, false); if (instanceCreatedWithInjection != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); return instanceCreatedWithInjection; } Log.Warning("Found constructor for type '{0}' in constructor, but it failed to create an instance. Removing the constructor from the cache", typeToConstruct.FullName); _constructorCache.Remove(constructorCacheKey); } Log.Debug("Creating instance of type '{0}'. No constructor found in the cache, so searching for the right one.", typeToConstruct.FullName); var typeConstructorsMetadata = GetTypeMetaData(typeToConstruct); var constructors = typeConstructorsMetadata.GetConstructors(); for (int i = 0; i < constructors.Count; i++) { var constructor = constructors[i]; var instanceCreatedWithInjection = TryCreateWithConstructorInjection(typeToConstruct, constructor, i < constructors.Count - 1); if (instanceCreatedWithInjection != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); // We found a constructor that works, cache it _constructorCache[constructorCacheKey] = constructor; return instanceCreatedWithInjection; } } var createdInstanceUsingActivator = CreateInstanceUsingActivator(typeToConstruct); if (createdInstanceUsingActivator != null) { CompleteTypeRequestPathIfRequired(typeRequestInfo); return createdInstanceUsingActivator; } } catch (CircularDependencyException) { throw; } catch (Exception ex) { CloseCurrentTypeIfRequired(typeRequestInfo); Log.Warning(ex, "Failed to construct type '{0}'", typeToConstruct.FullName); throw; } CloseCurrentTypeIfRequired(typeRequestInfo); return null; } }