private object CreateInstanceWithSpecifiedParameters(Type typeToConstruct, object tag, object[] parameters,
bool autoCompleteDependencies, bool preventCircularDependencies = true)
{
Argument.IsNotNull("typeToConstruct", typeToConstruct);
if (parameters == null)
{
parameters = new object[] { };
}
lock (_serviceLocator.LockObject)
{
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, tag, 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, tag, 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;
}
}