public static bool TryCreate(ContainerService.Builder builder) { if (!builder.Type.IsDelegate()) return false; if (!builder.Type.IsNestedPublic) return false; var invokeMethod = builder.Type.GetMethod("Invoke"); if (invokeMethod.ReturnType != builder.Type.DeclaringType) return false; var constructor = builder.Type.DeclaringType.GetConstructor(); if (!constructor.isOk) { builder.SetError(constructor.errorMessage); 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 = constructor.value.GetParameters(); var notBoundCtorParameters = ctorParameters .Where(x => x.ParameterType.IsSimpleType() && !delegateParameterNameToIndexMap.ContainsKey(x.Name)) .Select(x => x.Name) .ToArray(); if (notBoundCtorParameters.Length > 0) { builder.SetError(string.Format("ctor has not bound parameters [{0}]", notBoundCtorParameters.JoinStrings(","))); return true; } 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, constructor.value); il.Emit(OpCodes.Ret); var context = serviceTypeToIndex.Count == 0 ? null : services.ToArray(); builder.AddInstance(dynamicMethod.CreateDelegate(builder.Type, context), true); return true; }
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); }
private void InstantiateInterface(ContainerService.Builder builder) { var implementationTypes = GetImplementationTypes(builder); 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 = builder.CreateNew ? builder.Context.Instantiate(implementationType.type, true, builder.Arguments) : builder.Context.Resolve(ServiceName.Parse(implementationType.type, false)); 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 = ServiceDependency.NotResolved(null, implementationType.type.FormatName()); dependency.Comment = implementationType.comment; builder.AddDependency(dependency, true); } builder.EndResolveDependencies(); if (factory != null && canUseFactory) factoryCache.TryAdd(builder.GetName(), factory); }
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 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); 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 = builder.Context.Resolve(d).AsSingleInstanceDependency(null); 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 ? InternalHelpers.emptyStrings : builder.Arguments.GetUsed().Select(InternalHelpers.ByNameDependencyKey); var unusedConfigurationKeys = builder.Configuration.GetUnusedDependencyConfigurationKeys() .Except(dependenciesResolvedByArguments) .ToArray(); if (unusedConfigurationKeys.Length > 0) { 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.GetName(); if (builder.CreateNew || builder.DeclaredContracts.Length == builder.FinalUsedContracts.Length) { builder.CreateInstance(constructor.value, null, actualArguments); if (builder.CreateNew && builder.Arguments == null) { var compiledConstructor = constructor.value.Compile(); factoryCache.TryAdd(builder.GetName(), () => { var instance = compiledConstructor(null, actualArguments); var component = instance as IInitializable; if (component != null) component.Initialize(); return instance; }); } return; } var serviceForUsedContractsId = instanceCache.GetOrAdd(builder.GetName(), createId); ContainerService serviceForUsedContracts; if (serviceForUsedContractsId.AcquireInstantiateLock(out serviceForUsedContracts)) { builder.CreateInstance(constructor.value, null, actualArguments); serviceForUsedContracts = builder.Build(); serviceForUsedContractsId.ReleaseInstantiateLock(builder.Context.AnalizeDependenciesOnly ? null : serviceForUsedContracts); } else builder.Reuse(serviceForUsedContracts); }