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;
        }
예제 #2
0
 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);
 }
예제 #3
0
 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);
 }
예제 #4
0
 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);
 }
예제 #5
0
 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);
 }