private void InstantiateInterface(ContainerService.Builder builder) { HashSet <ImplementationType> implementationTypes; try { implementationTypes = GetImplementationTypes(builder); } catch (Exception e) { builder.SetError(e); return; } ApplySelectors(implementationTypes, builder); if (implementationTypes.Count == 0) { builder.SetComment("has no implementations"); return; } Func <object> factory = null; var canUseFactory = true; foreach (var implementationType in implementationTypes) { if (implementationType.accepted) { var implementationService = ResolveCore(ServiceName.Parse(implementationType.type, InternalHelpers.emptyStrings), builder.CreateNew, builder.Arguments, builder.Context); builder.LinkTo(containerContext, implementationService, implementationType.comment); if (builder.CreateNew && builder.Arguments == null && implementationService.Status == ServiceStatus.Ok && canUseFactory) { if (factory == null) { if (!factoryCache.TryGetValue(implementationService.Name, out factory)) { canUseFactory = false; } } else { canUseFactory = false; } } if (builder.Status.IsBad()) { return; } } else { var dependency = containerContext.NotResolved(null, implementationType.type.FormatName()); dependency.Comment = implementationType.comment; builder.AddDependency(dependency, true); } } builder.EndResolveDependencies(); if (factory != null && canUseFactory) { factoryCache.TryAdd(builder.GetFinalName(), factory); } }
internal ContainerService ResolveCore(ServiceName name, bool createNew, IObjectAccessor arguments, ResolutionContext context) { var pushedContracts = context.Contracts.Push(name.Contracts); var declaredName = new ServiceName(name.Type, context.Contracts.Snapshot()); if (context.HasCycle(declaredName)) { var message = string.Format("cyclic dependency for service [{0}], stack\r\n{1}", declaredName.Type.FormatName(), context.FormatStack() + "\r\n\t" + declaredName); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); return ContainerService.Error(declaredName, message); } if (!pushedContracts.isOk) { const string messageFormat = "contract [{0}] already declared, stack\r\n{1}"; var message = string.Format(messageFormat, pushedContracts.duplicatedContractName, context.FormatStack() + "\r\n\t" + name); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); return ContainerService.Error(name, message); } context.ConstructingServices.Add(declaredName); ServiceConfiguration configuration = null; Exception configurationException = null; try { configuration = GetConfiguration(declaredName.Type, context); } catch (Exception e) { configurationException = e; } var actualName = configuration != null && configuration.FactoryDependsOnTarget && context.Stack.Count > 0 ? declaredName.AddContracts(context.TopBuilder.Type.FormatName()) : declaredName; ContainerServiceId id = null; if (!createNew) { id = instanceCache.GetOrAdd(actualName, createId); var acquireResult = id.AcquireInstantiateLock(); if (!acquireResult.acquired) { context.ConstructingServices.Remove(declaredName); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); return acquireResult.alreadyConstructedService; } } var builder = new ContainerService.Builder(actualName); context.Stack.Add(builder); builder.Context = context; builder.DeclaredContracts = actualName.Contracts; if (configuration == null) builder.SetError(configurationException); else { builder.SetConfiguration(configuration); builder.ExpandedUnions = context.Contracts.TryExpandUnions(Configuration); if (builder.ExpandedUnions.HasValue) { var poppedContracts = context.Contracts.PopMany(builder.ExpandedUnions.Value.contracts.Length); foreach (var c in builder.ExpandedUnions.Value.contracts.CartesianProduct()) { var childService = ResolveCore(new ServiceName(name.Type, c), createNew, arguments, context); builder.LinkTo(containerContext, childService, null); if (builder.Status.IsBad()) break; } context.Contracts.PushNoCheck(poppedContracts); } else { builder.CreateNew = createNew; builder.Arguments = arguments; Instantiate(builder); } } context.ConstructingServices.Remove(declaredName); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); context.Stack.RemoveLast(); var result = builder.GetService(); if (id != null) id.ReleaseInstantiateLock(builder.Context.AnalizeDependenciesOnly ? null : result); return result; }
internal ContainerService ResolveCore(ServiceName name, bool createNew, IObjectAccessor arguments, ResolutionContext context) { var pushedContracts = context.Contracts.Push(name.Contracts); var declaredName = new ServiceName(name.Type, context.Contracts.Snapshot()); if (context.HasCycle(declaredName)) { var message = string.Format("cyclic dependency for service [{0}], stack\r\n{1}", declaredName.Type.FormatName(), context.FormatStack() + "\r\n\t" + declaredName); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); return(ContainerService.Error(declaredName, message)); } if (!pushedContracts.isOk) { const string messageFormat = "contract [{0}] already declared, stack\r\n{1}"; var message = string.Format(messageFormat, pushedContracts.duplicatedContractName, context.FormatStack() + "\r\n\t" + name); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); return(ContainerService.Error(name, message)); } context.ConstructingServices.Add(declaredName); ServiceConfiguration configuration = null; Exception configurationException = null; try { configuration = GetConfiguration(declaredName.Type, context); } catch (Exception e) { configurationException = e; } var actualName = configuration != null && configuration.FactoryDependsOnTarget && context.Stack.Count > 0 ? declaredName.AddContracts(context.TopBuilder.Type.FormatName()) : declaredName; ContainerServiceId id = null; if (!createNew) { id = instanceCache.GetOrAdd(actualName, createId); var acquireResult = id.AcquireInstantiateLock(); if (!acquireResult.acquired) { context.ConstructingServices.Remove(declaredName); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); return(acquireResult.alreadyConstructedService); } } var builder = new ContainerService.Builder(actualName); context.Stack.Add(builder); builder.Context = context; builder.DeclaredContracts = actualName.Contracts; if (configuration == null) { builder.SetError(configurationException); } else { builder.SetConfiguration(configuration); builder.ExpandedUnions = context.Contracts.TryExpandUnions(Configuration); if (builder.ExpandedUnions.HasValue) { var poppedContracts = context.Contracts.PopMany(builder.ExpandedUnions.Value.contracts.Length); foreach (var c in builder.ExpandedUnions.Value.contracts.CartesianProduct()) { var childService = ResolveCore(new ServiceName(name.Type, c), createNew, arguments, context); builder.LinkTo(containerContext, childService, null); if (builder.Status.IsBad()) { break; } } context.Contracts.PushNoCheck(poppedContracts); } else { builder.CreateNew = createNew; builder.Arguments = arguments; Instantiate(builder); } } context.ConstructingServices.Remove(declaredName); context.Contracts.RemoveLast(pushedContracts.pushedContractsCount); context.Stack.RemoveLast(); var result = builder.GetService(); if (id != null) { id.ReleaseInstantiateLock(builder.Context.AnalizeDependenciesOnly ? null : result); } return(result); }
public ContainerService Instantiate(Type type, bool crearteNew, IObjectAccessor arguments) { var builder = new ContainerService.Builder(type, this, crearteNew, arguments); if (builder.Status != ServiceStatus.Ok) return builder.Build(); var declaredName = builder.GetDeclaredName(); if (!constructingServices.Add(declaredName)) { var previous = GetTopBuilder(); if (previous == null) throw new InvalidOperationException(string.Format("assertion failure, service [{0}]", declaredName)); var message = string.Format("cyclic dependency {0}{1} -> {0}", type.FormatName(), previous.Type == type ? "" : " ...-> " + previous.Type.FormatName()); var cycleBuilder = new ContainerService.Builder(type, this, false, null); cycleBuilder.SetError(message); return cycleBuilder.Build(); } stack.Add(builder); var expandResult = TryExpandUnions(Container.Configuration); if (expandResult != null) { var poppedContracts = Contracts.PopMany(expandResult.Length); foreach (var c in expandResult.CartesianProduct()) { var childService = Resolve(new ServiceName(builder.Type, c)); builder.LinkTo(Container.containerContext, childService, null); if (builder.Status.IsBad()) break; } Contracts.AddRange(poppedContracts); } else Container.Instantiate(builder); stack.RemoveLast(); constructingServices.Remove(declaredName); return builder.Build(); }