Decorators with various constructor arguments

Using Castle Windsor, I would like to create a class that writes an integer. But I would like to decorate it with other classes several times. I see how this works if all the concrete used has dependencies that can be resolved, but it is not. Consider this code:

public interface IRecorder
{
    void Add(int value);
}

public class NotifyingRecorder : IRecorder
{
    readonly IRecorder decoratedRecorder;

    public NotifyingRecorder(IRecorder decoratedRecorder)
    {
        this.decoratedRecorder = decoratedRecorder;
    }

    public void Add(int value)
    {
        decoratedRecorder.Add(value);
        System.Console.WriteLine("Added " + value);
    }
}

public class ModelUpdatingRecorder : IRecorder
{
    int seed;

    public ModelUpdatingRecorder(int seed)
    {
        this.seed = seed;
    }

    public void Add(int value)
    {
        seed += value;
    }
}

And registered in:

container.Register(Component.For<IRecorder>().ImplementedBy<NotifyingRecorder>());
container.Register(Component.For<IRecorder>().ImplementedBy<ModelUpdatingRecorder>());

Permission IRecorderwill never work here, as it ModelUpdatingRecorderhas an optional dependency. I cannot use static dependency as it is seednot known at compile time.

Is there a way to specify a parameter seedat runtime and still work with the decor?

, . , - /, .

+1
2

(ISeedHolder?) . ModelUpdatingRecorder int. , ModelUpdatingRecorder

public interface ISeedHolder
{
    int Seed {get;set;}
}

public class ModelUpdatingRecorder : IRecorder
{
    int seed;

    public ModelUpdatingRecorder(ISeedHolder seedHolder)
    {
        this.seed = seedHolder.Seed;
    }

, ?

0

, , , . Windsor DefaultDependencyResolver , (, IRecorder ), RebuildContextForParameter. (.. ). :

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

    return new CreationContext(parameterType, current, false);
}

false CreationContext propagateInlineDependencies, , true current context AdditionalArguments, .

false true, , DefaultDependencyResolver:

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

        return new CreationContext(parameterType, current, true);
    }
}

Windsor:

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

NotSupportedProxyFactory DefaultComponentInstaller DefaultKernel WindsorContainer.

, , factory IRecorder, ..:

// during type registration/bootstrapping
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IRecorder>().ImplementedBy<NotifyingRecorder>());
container.Register(Component.For<IRecorder>().ImplementedBy<ModelUpdatingRecorder>());
container.Register(Component.For<IRecorderFactory>().AsFactory());

IRecorderFactory:

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

, :

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

, !

0

All Articles