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

后端 未结 7 756
一整个雨季
一整个雨季 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:20

    While I was waiting for answers on this, I came up with a rather hacky workaround. I've created an extension method on IUnityContainer that lets me register a decorator chain using reflection to create the InjectionConstructor parameters:

    static class DecoratorUnityExtensions
    {
        public static void RegisterDecoratorChain(this IUnityContainer container, Type[] decoratorChain)
        {
            Type parent = null;
            string parentName = null;
            foreach (Type t in decoratorChain)
            {
                string namedInstance = Guid.NewGuid().ToString();
                if (parent == null)
                {
                    // top level, just do an ordinary register type                    
                    container.RegisterType(typeof(T), t, namedInstance);
                }
                else
                {
                    // could be cleverer here. Just take first constructor
                    var constructor = t.GetConstructors()[0];
                    var resolvedParameters = new List();
                    foreach (var constructorParam in constructor.GetParameters())
                    {
                        if (constructorParam.ParameterType == typeof(T))
                        {
                            resolvedParameters.Add(new ResolvedParameter(parentName));
                        }
                        else
                        {
                            resolvedParameters.Add(new ResolvedParameter(constructorParam.ParameterType));
                        }
                    }
                    if (t == decoratorChain.Last())
                    {
                        // not a named instance
                        container.RegisterType(typeof(T), t, new InjectionConstructor(resolvedParameters.ToArray()));
                    }
                    else
                    {
                        container.RegisterType(typeof(T), t, namedInstance, new InjectionConstructor(resolvedParameters.ToArray()));
                    }
                }
                parent = t;
                parentName = namedInstance;
            }
        }
    }
    

    This allows me to configure my container with a much more readable syntax:

    [Test]
    public void ResolveWithDecorators2()
    {
        UnityContainer c = new UnityContainer();
        c.RegisterInstance(new Mock().Object);
        c.RegisterInstance(new Mock().Object);
        c.RegisterInstance(new Mock().Object);
    
        c.RegisterDecoratorChain(new Type[] { typeof(ProductRepository), typeof(CachingProductRepository), typeof(LoggingProductRepository) });
    
        Assert.IsInstanceOf(c.Resolve());
    
    }
    

    I'd still be interested to know if there is a more elegant solution to this with Unity

提交回复
热议问题