private void ApplySelectors(HashSet <ImplementationType> implementations, ContainerService.Builder builder) { if (builder.Configuration != ServiceConfiguration.empty) { return; } if (implementationSelectors.Count == 0) { return; } var selectorDecisions = new List <ImplementationSelectorDecision>(); var typesArray = implementations.Select(x => x.type).ToArray(); foreach (var s in implementationSelectors) { s(builder.Type, typesArray, selectorDecisions); } foreach (var decision in selectorDecisions) { var item = new ImplementationType { type = decision.target, comment = decision.comment, accepted = decision.action == ImplementationSelectorDecision.Action.Include }; implementations.Replace(item); } }
public static object TryCreate(ContainerService.Builder builder) { if (!builder.Type.IsGenericType) { return(null); } if (builder.Type.GetGenericTypeDefinition() != typeof(Lazy <>)) { return(null); } var resultType = builder.Type.GetGenericArguments()[0]; if (builder.Context.Contracts.Count() > 0) { var oldValue = builder.Context.AnalizeDependenciesOnly; builder.Context.AnalizeDependenciesOnly = true; var containerService = builder.Context.Container.ResolveCore(new ServiceName(resultType), true, null, builder.Context); builder.Context.AnalizeDependenciesOnly = oldValue; builder.UnionUsedContracts(containerService); } var lazyFactoryCtor = typeof(LazyFactory <>).MakeGenericType(resultType).GetConstructors().Single(); var lazyFactory = (ILazyFactory)lazyFactoryCtor.Compile()(null, new object[] { builder.Context.Container }); return(lazyFactory.CreateLazy()); }
internal void Instantiate(ContainerService.Builder builder) { LifestyleAttribute lifestyle; if (builder.Type.IsSimpleType()) { builder.SetError("can't create simple type"); } else if (builder.Type == typeof(IContainer)) { builder.AddInstance(this, false, false); } else if (builder.Configuration.ImplementationAssigned) { builder.AddInstance(builder.Configuration.Implementation, builder.Configuration.ContainerOwnsInstance, true); } else if (builder.Configuration.Factory != null) { if (!builder.Context.AnalizeDependenciesOnly) { builder.CreateInstanceBy(CallTarget.F(builder.Configuration.Factory), builder.Configuration.ContainerOwnsInstance); } } else if (builder.Type.IsValueType) { builder.SetError("can't create value type"); } else if (builder.Type.IsGenericType && builder.Type.ContainsGenericParameters) { builder.SetError("can't create open generic"); } else if (!builder.CreateNew && builder.Type.TryGetCustomAttribute(out lifestyle) && lifestyle.Lifestyle == Lifestyle.PerRequest) { const string messageFormat = "service [{0}] with PerRequest lifestyle can't be resolved, use Func<{0}> instead"; builder.SetError(string.Format(messageFormat, builder.Type.FormatName())); } else if (builder.Type.IsAbstract) { InstantiateInterface(builder); } else { InstantiateImplementation(builder); } }
public static object TryCreate(ContainerService.Builder builder) { var funcType = builder.Type; if (!funcType.IsGenericType || !funcType.IsDelegate()) { return(null); } Type resultType; var signature = FindSignature(funcType, out resultType); if (signature == null) { return(null); } var factory = CreateFactory(builder, resultType); var caster = casters.GetOrAdd(new SignatureDelegateKey(resultType, signature), createCaster); var typedCaster = (Func <Func <Type, object, object>, object>)caster; return(typedCaster(factory)); }
public static bool TryCreate(ContainerService.Builder builder) { var factoryType = builder.Type.GetNestedType("Factory"); if (factoryType == null) { return(false); } var method = factoryType.GetMethod("Create", Type.EmptyTypes); if (method == null) { return(false); } var factory = builder.Context.Container.Resolve(method.DeclaringType, InternalHelpers.emptyStrings, false); if (factory.IsOk()) { builder.CreateInstanceBy(CallTarget.M(method, factory.Single(), new object[0]), true); } return(true); }
private static Func <Type, object, object> CreateFactory(ContainerService.Builder builder, Type resultType) { var container = builder.Context.Container; if (builder.Context.Contracts.Count() > 0) { var oldValue = builder.Context.AnalizeDependenciesOnly; builder.Context.AnalizeDependenciesOnly = true; var containerService = builder.Context.Container.ResolveCore(new ServiceName(resultType), true, null, builder.Context); builder.Context.AnalizeDependenciesOnly = oldValue; builder.UnionUsedContracts(containerService); } builder.EndResolveDependencies(); var factoryContractsArray = builder.FinalUsedContracts; return((type, arguments) => { var name = ServiceName.Parse(type.UnwrapEnumerable(), factoryContractsArray); return container.Create(name, name.Type != type, arguments); }); }
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(); }
internal ServiceDependency InstantiateDependency(ParameterInfo formalParameter, ContainerService.Builder builder) { ValueWithType actualArgument; if (builder.Arguments != null && builder.Arguments.TryGet(formalParameter.Name, out actualArgument)) { return(containerContext.Constant(formalParameter, actualArgument.value)); } var parameters = builder.Configuration.ParametersSource; object actualParameter; if (parameters != null && parameters.TryGet(formalParameter.Name, formalParameter.ParameterType, out actualParameter)) { return(containerContext.Constant(formalParameter, actualParameter)); } var dependencyConfiguration = builder.Configuration.GetOrNull(formalParameter); Type implementationType = null; if (dependencyConfiguration != null) { if (dependencyConfiguration.ValueAssigned) { return(containerContext.Constant(formalParameter, dependencyConfiguration.Value)); } if (dependencyConfiguration.Factory != null) { var dependencyBuilder = new ContainerService.Builder(new ServiceName(formalParameter.ParameterType)) { Context = builder.Context, DependencyName = formalParameter.Name }; builder.Context.Stack.Add(dependencyBuilder); dependencyBuilder.CreateInstanceBy(CallTarget.F(dependencyConfiguration.Factory), true); builder.Context.Stack.RemoveLast(); return(dependencyBuilder.GetService().AsDependency(containerContext, formalParameter.Name, false)); } implementationType = dependencyConfiguration.ImplementationType; } implementationType = implementationType ?? formalParameter.ParameterType; FromResourceAttribute resourceAttribute; if (implementationType == typeof(Stream) && formalParameter.TryGetCustomAttribute(out resourceAttribute)) { var resourceStream = builder.Type.Assembly.GetManifestResourceStream(builder.Type, resourceAttribute.Name); if (resourceStream == null) { return(containerContext.Error(null, formalParameter.Name, "can't find resource [{0}] in namespace of [{1}], assembly [{2}]", resourceAttribute.Name, builder.Type, builder.Type.Assembly.GetName().Name)); } return(containerContext.Resource(formalParameter, resourceAttribute.Name, resourceStream)); } var dependencyName = ServiceName.Parse(implementationType.UnwrapEnumerable(), InternalHelpers.ParseContracts(formalParameter)); if (dependencyName.Type.IsSimpleType()) { if (!formalParameter.HasDefaultValue) { return(containerContext.Error(null, formalParameter.Name, "parameter [{0}] of service [{1}] is not configured", formalParameter.Name, builder.Type.FormatName())); } return(containerContext.Constant(formalParameter, formalParameter.DefaultValue)); } var resultService = ResolveCore(dependencyName, false, null, builder.Context); if (resultService.Status.IsBad()) { return(containerContext.ServiceError(resultService)); } var isEnumerable = dependencyName.Type != implementationType; if (isEnumerable) { return(containerContext.Service(resultService, resultService.GetAllValues())); } if (resultService.Status == ServiceStatus.NotResolved) { if (formalParameter.HasDefaultValue) { return(containerContext.Service(resultService, formalParameter.DefaultValue)); } if (formalParameter.IsDefined <OptionalAttribute>() || formalParameter.IsDefined("CanBeNullAttribute")) { return(containerContext.Service(resultService, null)); } return(containerContext.NotResolved(resultService)); } return(resultService.AsDependency(containerContext, null, false)); }
private void InstantiateImplementation(ContainerService.Builder builder) { if (builder.DontUse()) { builder.SetComment("DontUse"); return; } var result = FactoryCreator.TryCreate(builder) ?? LazyCreator.TryCreate(builder); if (result != null) { builder.AddInstance(result, true, false); return; } if (NestedFactoryCreator.TryCreate(builder)) { return; } if (CtorFactoryCreator.TryCreate(builder)) { return; } if (builder.Type.IsDelegate()) { builder.SetError(string.Format("can't create delegate [{0}]", builder.Type.FormatName())); return; } var constructor = builder.Type.GetConstructor(); if (!constructor.isOk) { builder.SetError(constructor.errorMessage); return; } var formalParameters = constructor.value.GetParameters(); var actualArguments = new object[formalParameters.Length]; var hasServiceNameParameters = false; for (var i = 0; i < formalParameters.Length; i++) { var formalParameter = formalParameters[i]; if (formalParameter.ParameterType == typeof(ServiceName)) { hasServiceNameParameters = true; continue; } var dependency = InstantiateDependency(formalParameter, builder).CastTo(formalParameter.ParameterType); builder.AddDependency(dependency, false); if (dependency.ContainerService != null) { builder.UnionUsedContracts(dependency.ContainerService); } if (builder.Status != ServiceStatus.Ok && !builder.Context.AnalizeDependenciesOnly) { return; } actualArguments[i] = dependency.Value; } foreach (var d in builder.Configuration.ImplicitDependencies) { var dependency = ResolveCore(ServiceName.Parse(d.Type, d.Contracts), false, null, builder.Context) .AsDependency(containerContext, null, false); dependency.Comment = "implicit"; builder.AddDependency(dependency, false); if (dependency.ContainerService != null) { builder.UnionUsedContracts(dependency.ContainerService); } if (builder.Status != ServiceStatus.Ok) { return; } } builder.EndResolveDependencies(); if (builder.Context.AnalizeDependenciesOnly) { return; } var dependenciesResolvedByArguments = builder.Arguments == null ? null : builder.Arguments.GetUsed(); List <string> unusedConfigurationKeys = null; foreach (var k in builder.Configuration.GetUnusedDependencyKeys()) { var resolvedByArguments = dependenciesResolvedByArguments != null && k.name != null && dependenciesResolvedByArguments.Contains(k.name); if (resolvedByArguments) { continue; } if (unusedConfigurationKeys == null) { unusedConfigurationKeys = new List <string>(); } unusedConfigurationKeys.Add(k.ToString()); } if (unusedConfigurationKeys != null) { builder.SetError(string.Format("unused dependency configurations [{0}]", unusedConfigurationKeys.JoinStrings(","))); return; } if (hasServiceNameParameters) { for (var i = 0; i < formalParameters.Length; i++) { if (formalParameters[i].ParameterType == typeof(ServiceName)) { actualArguments[i] = builder.GetFinalName(); } } } if (builder.CreateNew || builder.DeclaredContracts.Length == builder.FinalUsedContracts.Length) { builder.CreateInstanceBy(CallTarget.M(constructor.value, null, actualArguments), true); if (builder.CreateNew && builder.Arguments == null) { var compiledConstructor = constructor.value.Compile(); factoryCache.TryAdd(builder.GetFinalName(), () => { var instance = compiledConstructor(null, actualArguments); var component = instance as IInitializable; if (component != null) { component.Initialize(); } return(instance); }); } return; } var serviceForUsedContractsId = instanceCache.GetOrAdd(builder.GetFinalName(), createId); var acquireResult = serviceForUsedContractsId.AcquireInstantiateLock(); if (acquireResult.acquired) { builder.CreateInstanceBy(CallTarget.M(constructor.value, null, actualArguments), true); serviceForUsedContractsId.ReleaseInstantiateLock(builder.Context.AnalizeDependenciesOnly ? null : builder.GetService()); } else { builder.Reuse(acquireResult.alreadyConstructedService); } }
private HashSet <ImplementationType> GetImplementationTypes(ContainerService.Builder builder) { var result = new HashSet <ImplementationType>(); var candidates = builder.Configuration.ImplementationTypes ?? containerContext.typesList.InheritorsOf(builder.Type.GetDefinition()); var implementationTypesAreExplicitlyConfigured = builder.Configuration.ImplementationTypes != null; foreach (var implType in candidates) { if (!implementationTypesAreExplicitlyConfigured) { var configuration = GetConfiguration(implType, builder.Context); if (configuration.IgnoredImplementation || implType.IsDefined("IgnoredImplementationAttribute")) { result.Add(new ImplementationType { type = implType, comment = "IgnoredImplementation", accepted = false }); } } if (!implType.IsGenericType) { if (!builder.Type.IsGenericType || builder.Type.IsAssignableFrom(implType)) { result.Add(ImplementationType.Accepted(implType)); } } else if (!implType.ContainsGenericParameters) { result.Add(ImplementationType.Accepted(implType)); } else { var mapped = containerContext.genericsAutoCloser.AutoCloseDefinition(implType); foreach (var type in mapped) { if (builder.Type.IsAssignableFrom(type)) { result.Add(ImplementationType.Accepted(type)); } } if (builder.Type.IsGenericType) { var implInterfaces = implType.ImplementationsOf(builder.Type.GetGenericTypeDefinition()); foreach (var implInterface in implInterfaces) { var closed = implType.TryCloseByPattern(implInterface, builder.Type); if (closed != null) { result.Add(ImplementationType.Accepted(closed)); } } } if (builder.Arguments == null) { continue; } var serviceConstructor = implType.GetConstructor(); if (!serviceConstructor.isOk) { continue; } foreach (var formalParameter in serviceConstructor.value.GetParameters()) { if (!formalParameter.ParameterType.ContainsGenericParameters) { continue; } ValueWithType parameterValue; if (!builder.Arguments.TryGet(formalParameter.Name, out parameterValue)) { continue; } var parameterType = parameterValue.value == null ? parameterValue.type : parameterValue.value.GetType(); var implInterfaces = formalParameter.ParameterType.IsGenericParameter ? new List <Type>(1) { parameterType } : parameterType.ImplementationsOf(formalParameter.ParameterType.GetGenericTypeDefinition()); foreach (var implInterface in implInterfaces) { var closedItem = implType.TryCloseByPattern(formalParameter.ParameterType, implInterface); if (closedItem != null) { result.Add(ImplementationType.Accepted(closedItem)); } } } } } return(result); }
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; }
internal ServiceDependency InstantiateDependency(ParameterInfo formalParameter, ContainerService.Builder builder) { ValueWithType actualArgument; if (builder.Arguments != null && builder.Arguments.TryGet(formalParameter.Name, out actualArgument)) return containerContext.Constant(formalParameter, actualArgument.value); var parameters = builder.Configuration.ParametersSource; object actualParameter; if (parameters != null && parameters.TryGet(formalParameter.Name, formalParameter.ParameterType, out actualParameter)) return containerContext.Constant(formalParameter, actualParameter); var dependencyConfiguration = builder.Configuration.GetOrNull(formalParameter); Type implementationType = null; if (dependencyConfiguration != null) { if (dependencyConfiguration.ValueAssigned) return containerContext.Constant(formalParameter, dependencyConfiguration.Value); if (dependencyConfiguration.Factory != null) { var dependencyBuilder = new ContainerService.Builder(new ServiceName(formalParameter.ParameterType)) { Context = builder.Context, DependencyName = formalParameter.Name }; builder.Context.Stack.Add(dependencyBuilder); dependencyBuilder.CreateInstanceBy(CallTarget.F(dependencyConfiguration.Factory), true); builder.Context.Stack.RemoveLast(); return dependencyBuilder.GetService().AsDependency(containerContext, formalParameter.Name, false); } implementationType = dependencyConfiguration.ImplementationType; } implementationType = implementationType ?? formalParameter.ParameterType; FromResourceAttribute resourceAttribute; if (implementationType == typeof (Stream) && formalParameter.TryGetCustomAttribute(out resourceAttribute)) { var resourceStream = builder.Type.Assembly.GetManifestResourceStream(builder.Type, resourceAttribute.Name); if (resourceStream == null) return containerContext.Error(null, formalParameter.Name, "can't find resource [{0}] in namespace of [{1}], assembly [{2}]", resourceAttribute.Name, builder.Type, builder.Type.Assembly.GetName().Name); return containerContext.Resource(formalParameter, resourceAttribute.Name, resourceStream); } var dependencyName = ServiceName.Parse(implementationType.UnwrapEnumerable(), InternalHelpers.ParseContracts(formalParameter)); if (dependencyName.Type.IsSimpleType()) { if (!formalParameter.HasDefaultValue) return containerContext.Error(null, formalParameter.Name, "parameter [{0}] of service [{1}] is not configured", formalParameter.Name, builder.Type.FormatName()); return containerContext.Constant(formalParameter, formalParameter.DefaultValue); } var resultService = ResolveCore(dependencyName, false, null, builder.Context); if (resultService.Status.IsBad()) return containerContext.ServiceError(resultService); var isEnumerable = dependencyName.Type != implementationType; if (isEnumerable) return containerContext.Service(resultService, resultService.GetAllValues()); if (resultService.Status == ServiceStatus.NotResolved) { if (formalParameter.HasDefaultValue) return containerContext.Service(resultService, formalParameter.DefaultValue); if (formalParameter.IsDefined<OptionalAttribute>() || formalParameter.IsDefined("CanBeNullAttribute")) return containerContext.Service(resultService, null); return containerContext.NotResolved(resultService); } return resultService.AsDependency(containerContext, null, false); }
public ContainerService Resolve(ServiceName name) { if (name.Contracts.Length == 0) return Container.ResolveSingleton(name.Type, this); var pushedCount = 0; foreach (var newContract in name.Contracts) { foreach (var c in Contracts) if (newContract.EqualsIgnoringCase(c)) { var resultBuilder = new ContainerService.Builder(name.Type, this, false, null); const string messageFormat = "contract [{0}] already declared, all declared contracts [{1}]"; resultBuilder.SetError(string.Format(messageFormat, newContract, InternalHelpers.FormatContractsKey(Contracts))); Contracts.RemoveLast(pushedCount); return resultBuilder.Build(); } Contracts.Add(newContract); pushedCount++; } var result = Container.ResolveSingleton(name.Type, this); Contracts.RemoveLast(name.Contracts.Length); return result; }
public static bool TryCreate(ContainerService.Builder builder) { if (!builder.Type.IsDelegate() || builder.Type.FullName.StartsWith("System.Func`")) { return(false); } var invokeMethod = builder.Type.GetMethod("Invoke"); if (!builder.Type.IsNestedPublic) { builder.SetError(string.Format("can't create delegate [{0}]. must be nested public", builder.Type.FormatName())); return(true); } if (invokeMethod.ReturnType != builder.Type.DeclaringType) { builder.SetError(string.Format("can't create delegate [{0}]. return type must match declaring", builder.Type.FormatName())); return(true); } const BindingFlags ctorBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; var constructors = builder.Type.DeclaringType.GetConstructors(ctorBindingFlags) .Where(x => Match(invokeMethod, x)) .ToArray(); if (constructors.Length == 0) { builder.SetError("can't find matching ctor"); return(true); } if (constructors.Length > 1) { builder.SetError("more than one matched ctors found"); return(true); } var delegateParameters = invokeMethod.GetParameters(); var delegateParameterNameToIndexMap = new Dictionary <string, int>(); for (var i = 0; i < delegateParameters.Length; i++) { delegateParameterNameToIndexMap[delegateParameters[i].Name] = i; } var dynamicMethodParameterTypes = new Type[delegateParameters.Length + 1]; dynamicMethodParameterTypes[0] = typeof(object[]); for (var i = 1; i < dynamicMethodParameterTypes.Length; i++) { dynamicMethodParameterTypes[i] = delegateParameters[i - 1].ParameterType; } var dynamicMethod = new DynamicMethod("", invokeMethod.ReturnType, dynamicMethodParameterTypes, typeof(ReflectionHelpers), true); var il = dynamicMethod.GetILGenerator(); var ctorParameters = constructors[0].GetParameters(); var serviceTypeToIndex = new Dictionary <Type, int>(); var services = new List <object>(); foreach (var p in ctorParameters) { int delegateParameterIndex; if (delegateParameterNameToIndexMap.TryGetValue(p.Name, out delegateParameterIndex)) { var delegateParameterType = delegateParameters[delegateParameterIndex].ParameterType; if (!p.ParameterType.IsAssignableFrom(delegateParameterType)) { const string messageFormat = "type mismatch for [{0}], delegate type [{1}], ctor type [{2}]"; builder.SetError(string.Format(messageFormat, p.Name, delegateParameterType.FormatName(), p.ParameterType.FormatName())); return(true); } il.EmitLdArg(delegateParameterIndex + 1); delegateParameterNameToIndexMap.Remove(p.Name); } else { int serviceIndex; if (!serviceTypeToIndex.TryGetValue(p.ParameterType, out serviceIndex)) { object value; if (p.ParameterType == typeof(ServiceName)) { value = null; } else { var dependency = builder.Context.Container.InstantiateDependency(p, builder).CastTo(p.ParameterType); builder.AddDependency(dependency, false); if (dependency.ContainerService != null) { builder.UnionUsedContracts(dependency.ContainerService); } if (builder.Status != ServiceStatus.Ok) { return(true); } value = dependency.Value; } serviceIndex = serviceTypeToIndex.Count; serviceTypeToIndex.Add(p.ParameterType, serviceIndex); services.Add(value); } il.Emit(OpCodes.Ldarg_0); il.EmitLdInt32(serviceIndex); il.Emit(OpCodes.Ldelem_Ref); il.Emit(p.ParameterType.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, p.ParameterType); } } if (delegateParameterNameToIndexMap.Count > 0) { builder.SetError(string.Format("delegate has not used parameters [{0}]", delegateParameterNameToIndexMap.Keys.JoinStrings(","))); return(true); } builder.EndResolveDependencies(); int serviceNameIndex; if (serviceTypeToIndex.TryGetValue(typeof(ServiceName), out serviceNameIndex)) { services[serviceNameIndex] = new ServiceName(builder.Type.DeclaringType, builder.FinalUsedContracts); } il.Emit(OpCodes.Newobj, constructors[0]); il.Emit(OpCodes.Ret); var context = serviceTypeToIndex.Count == 0 ? null : services.ToArray(); builder.AddInstance(dynamicMethod.CreateDelegate(builder.Type, context), true, false); return(true); }