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);
            }
        }
示例#2
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());
        }
        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);
            }
        }
示例#4
0
        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));
        }
示例#5
0
        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);
        }
示例#6
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);
            });
        }
 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;
 }
示例#16
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);
        }