Example #1
0
        Expression IRegistry.GetDecoratorExpressionOrDefault(Request request)
        {
            // Decorators for non service types are not supported.
            if (request.FactoryType != FactoryType.Service)
                return null;

            // We are already resolving decorator for the service, so stop now.
            var parent = request.GetNonWrapperParentOrDefault();
            if (parent != null && parent.DecoratedFactoryID == request.FactoryID)
                return null;

            var serviceType = request.ServiceType;
            var decoratorFuncType = typeof(Func<,>).MakeGenericType(serviceType, serviceType);

            LambdaExpression resultFuncDecorator = null;
            var funcDecorators = _decorators.GetValueOrDefault(decoratorFuncType);
            if (funcDecorators != null)
            {
                var decoratorRequest = request.MakeDecorated();
                for (var i = 0; i < funcDecorators.Length; i++)
                {
                    var decorator = funcDecorators[i].Factory;
                    if (((DecoratorSetup)decorator.Setup).IsApplicable(request))
                    {
                        var newDecorator = decorator.GetExpression(decoratorRequest, this);
                        if (resultFuncDecorator == null)
                        {
                            var decorated = Expression.Parameter(serviceType, "decorated");
                            resultFuncDecorator = Expression.Lambda(Expression.Invoke(newDecorator, decorated), decorated);
                        }
                        else
                        {
                            var decorateDecorator = Expression.Invoke(newDecorator, resultFuncDecorator.Body);
                            resultFuncDecorator = Expression.Lambda(decorateDecorator, resultFuncDecorator.Parameters[0]);
                        }
                    }
                }
            }

            IEnumerable<DecoratorsEntry> decorators = _decorators.GetValueOrDefault(serviceType);
            var openGenericDecoratorIndex = decorators == null ? 0 : ((DecoratorsEntry[])decorators).Length;
            if (request.OpenGenericServiceType != null)
            {
                var openGenericDecorators = _decorators.GetValueOrDefault(request.OpenGenericServiceType);
                if (openGenericDecorators != null)
                    decorators = decorators == null ? openGenericDecorators : decorators.Concat(openGenericDecorators);
            }

            Expression resultDecorator = resultFuncDecorator;
            if (decorators != null)
            {
                var decoratorRequest = request.MakeDecorated();
                var decoratorIndex = 0;
                var enumerator = decorators.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    var decorator = enumerator.Current.ThrowIfNull();
                    var factory = decorator.Factory;
                    if (((DecoratorSetup)factory.Setup).IsApplicable(request))
                    {
                        // Cache closed generic registration produced by open-generic decorator.
                        if (decoratorIndex++ >= openGenericDecoratorIndex)
                            factory = Register(factory.GetFactoryPerRequestOrDefault(request, this), serviceType, null);

                        if (decorator.CachedExpression == null)
                        {
                            IList<Type> unusedFunArgs;
                            var funcExpr = factory
                                .GetFuncWithArgsOrDefault(decoratorFuncType, decoratorRequest, this, out unusedFunArgs)
                                .ThrowIfNull(Error.DECORATOR_FACTORY_SHOULD_SUPPORT_FUNC_RESOLUTION, decoratorFuncType);

                            decorator.CachedExpression = unusedFunArgs != null ? funcExpr.Body : funcExpr;
                        }

                        if (resultDecorator == null || !(decorator.CachedExpression is LambdaExpression))
                            resultDecorator = decorator.CachedExpression;
                        else
                        {
                            if (!(resultDecorator is LambdaExpression))
                                resultDecorator = Expression.Invoke(decorator.CachedExpression, resultDecorator);
                            else
                            {
                                var prevDecorators = ((LambdaExpression)resultDecorator);
                                var decorateDecorator = Expression.Invoke(decorator.CachedExpression, prevDecorators.Body);
                                resultDecorator = Expression.Lambda(decorateDecorator, prevDecorators.Parameters[0]);
                            }
                        }
                    }
                }
            }

            return resultDecorator;
        }