How do I use the Decorator Pattern with Unity without explicitly specifying every parameter in the InjectionConstructor

后端 未结 7 748
一整个雨季
一整个雨季 2020-12-01 03:09

This helpful article from David Haydn (EDIT: scam link removed, it could have been this article) shows how you can use the InjectionConstructor class to help y

7条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-01 03:37

    I knocked up a fairly crude extension method for this, which behaved as expected when I ran it:

    public static class UnityExtensions
    {
        public static IUnityContainer Decorate(this IUnityContainer container, params InjectionMember[] injectionMembers)
            where TDecorator : class, TInterface
        {
            return Decorate(container, null, injectionMembers);
        }
    
        public static IUnityContainer Decorate(this IUnityContainer container, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
            where TDecorator : class, TInterface
        {
            string uniqueId = Guid.NewGuid().ToString();
            var existingRegistration = container.Registrations.LastOrDefault(r => r.RegisteredType == typeof(TInterface));
            if(existingRegistration == null)
            {
                throw new ArgumentException("No existing registration found for the type " + typeof(TInterface));
            }
            var existing = existingRegistration.MappedToType;
    
            //1. Create a wrapper. This is the actual resolution that will be used
            if (lifetimeManager != null)
            {
                container.RegisterType(uniqueId, lifetimeManager, injectionMembers);
            }
            else
            {
                container.RegisterType(uniqueId, injectionMembers);
            }
    
            //2. Unity comes here to resolve TInterface
            container.RegisterType(new InjectionFactory((c, t, sName) =>
            {
                //3. We get the decorated class instance TBase
                var baseObj = container.Resolve(existing);
    
                //4. We reference the wrapper TDecorator injecting TBase as TInterface to prevent stack overflow
                return c.Resolve(uniqueId, new DependencyOverride(baseObj));
            }));
    
            return container;
        }
    }
    

    And in your setup:

    container.RegisterType();
    
    // Wrap ProductRepository with CachingProductRepository,
    // injecting ProductRepository into CachingProductRepository for
    // IProductRepository
    container.Decorate();
    
    // Wrap CachingProductRepository with LoggingProductRepository,
    // injecting CachingProductRepository into LoggingProductRepository for
    // IProductRepository
    container.Decorate();
    

提交回复
热议问题