Decorators with different constructor arguments

前端 未结 2 575
野的像风
野的像风 2021-01-16 04:05

Using Castle Windsor, I\'d like to create a class that records an integer. But I\'d like to decorate it several times with other classes. I can see how this works if all c

2条回答
  •  离开以前
    2021-01-16 05:09

    I've found a solution that I believe is the way this should be done. Down in the innards of Windsor the DefaultDependencyResolver has a method it uses to resolve sub-dependencies (such as a decorated instance of IRecorder above) called RebuildContextForParameter. It calls this to create a new context to use when resolving the dependency (i.e. the parameter to the constructor). The method is:

    /// This method rebuild the context for the parameter type. Naive implementation.
    protected virtual CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
    {
        if (parameterType.ContainsGenericParameters)
        {
            return current;
        }
    
        return new CreationContext(parameterType, current, false);
    }
    

    The false parameter in CreationContext constructor is propagateInlineDependencies, which when true will copy over the current context's AdditionalArguments, thereby passing down the parameters to the sub-dependencies.

    To flip this false to true, create a new class that derives from DefaultDependencyResolver:

    public class DefaultDependencyResolverInheritContext : DefaultDependencyResolver
    {
        protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
        {
            if (parameterType.ContainsGenericParameters)
            {
                return current;
            }
    
            return new CreationContext(parameterType, current, true);
        }
    }
    

    Then use that when creating the Windsor container:

    var kernel = new DefaultKernel(
                     new DefaultDependencyResolverInheritContext(), 
                     new NotSupportedProxyFactory());
    var container = new WindsorContainer(kernel, new DefaultComponentInstaller());
    

    The NotSupportedProxyFactory and DefaultComponentInstaller are the defaults when using the parameter-less constructors for DefaultKernel and WindsorContainer.

    When done, the code above will work when a factory is used to create an IRecorder, i.e.:

    // during type registration/bootstrapping
    container.AddFacility();
    container.Register(Component.For().ImplementedBy());
    container.Register(Component.For().ImplementedBy());
    container.Register(Component.For().AsFactory());
    

    Where IRecorderFactory is:

    public interface IRecorderFactory
    {
        IRecorder Create(int seed);
    }
    

    Then this will work as expected:

    IRecorderFactory recorderFactory = container.Resolve();
    IRecorder recorder = recorderFactory.Create(20);
    recorder.Add(6);
    

    Hopefully that helps others!

提交回复
热议问题