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