private void SetConstructor(ConstructorCacheKey cacheKey, ConstructorCacheValue previousCacheValue, ConstructorInfo constructorInfo) { // Currently I choose last-win strategy but maybe other should be used _constructorCacheLock.PerformWrite(() => { ConstructorCacheValue storedValue; if (!_constructorCache.TryGetValue(cacheKey, out storedValue)) { storedValue = ConstructorCacheValue.First(); } if (storedValue.Version == previousCacheValue.Version) { // Log.Debug("Everything is fine"); } else if (storedValue.Version > previousCacheValue.Version) { Log.Debug("Data in cache have been changed between read & write."); } else { // TODO: Maybe exception should be thrown Log.Debug("Something strange have happend. Deep log analyze required."); } // I'm not sure storedValue or previousCacheValue should be passed in here var cacheValue = ConstructorCacheValue.Next(storedValue, constructorInfo); _constructorCache[cacheKey] = cacheValue; }); }
private bool Equals(ConstructorCacheKey other) { if (AutoCompleteDependecies != other.AutoCompleteDependecies) { return(false); } return(string.Equals(Key, other.Key, StringComparison.Ordinal)); }
private ConstructorCacheValue GetConstructor(ConstructorCacheKey cacheKey) { return(_constructorCacheLock.PerformRead(() => { ConstructorCacheValue result; if (_constructorCache.TryGetValue(cacheKey, out result)) { return result; } return ConstructorCacheValue.First(); })); }
/// <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="autoCompleteDependencies">if set to <c>true</c>, the additional dependencies will be auto completed.</param> /// <param name="parameters">The parameters to inject.</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, bool autoCompleteDependencies, object[] parameters) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { var constructorCache = GetConstructorCache(autoCompleteDependencies); var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, parameters); if (constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateWithConstructorInjectionWithParameters(typeToConstruct, cachedConstructor, parameters); 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); 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); foreach (var constructor in constructors) { // Check if this constructor is even possible if (!CanConstructorBeUsed(constructor, autoCompleteDependencies, parameters)) { continue; } Log.Debug("Using constructor '{0}' to construct type '{1}'", constructor.GetSignature(), typeToConstruct.FullName); var instanceCreatedWithInjection = TryCreateWithConstructorInjectionWithParameters(typeToConstruct, constructor, parameters); if (instanceCreatedWithInjection != null) { // We found a constructor that works, cache it constructorCache[constructorCacheKey] = constructor; return(instanceCreatedWithInjection); } } Log.Debug("No constructor could be used, cannot construct type '{0}' with the specified parameters", typeToConstruct.FullName); return(null); } }
private bool Equals(ConstructorCacheKey other) { return(string.Equals(Key, other.Key, StringComparison.Ordinal)); }
/// <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="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 == 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); }
private bool Equals(ConstructorCacheKey other) { return string.Equals(Key, other.Key, StringComparison.Ordinal); }
/// <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 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); } }
/// <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="autoCompleteDependencies">if set to <c>true</c>, the additional dependencies will be auto completed.</param> /// <param name="parameters">The parameters to inject.</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, bool autoCompleteDependencies, object[] parameters) { Argument.IsNotNull("typeToConstruct", typeToConstruct); lock (_lockObject) { var constructorCache = GetConstructorCache(autoCompleteDependencies); var constructorCacheKey = new ConstructorCacheKey(typeToConstruct, parameters); if (constructorCache.ContainsKey(constructorCacheKey)) { var cachedConstructor = constructorCache[constructorCacheKey]; var instanceCreatedWithInjection = TryCreateWithConstructorInjectionWithParameters(typeToConstruct, cachedConstructor, parameters); 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); 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); foreach (var constructor in constructors) { // Check if this constructor is even possible if (!CanConstructorBeUsed(constructor, autoCompleteDependencies, parameters)) { continue; } Log.Debug("Using constructor '{0}' to construct type '{1}'", constructor.GetSignature(), typeToConstruct.FullName); var instanceCreatedWithInjection = TryCreateWithConstructorInjectionWithParameters(typeToConstruct, constructor, parameters); if (instanceCreatedWithInjection != null) { // We found a constructor that works, cache it constructorCache[constructorCacheKey] = constructor; return instanceCreatedWithInjection; } } Log.Debug("No constructor could be used, cannot construct type '{0}' with the specified parameters", typeToConstruct.FullName); 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 { 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; } }