Registering open generic decorators for typed implementations at Windsor Castle

While trying to get Windsor to wrap an implementation with a random number of decorators, I came across the following:

I have 3 decorators and an implementation using the same interface.

if you run this code windsor resolves icommandhandler<stringcommand>

like implementation

, which is the expected behavior as far as I can tell, because a typed implementation cannot be registered with public typed decorators.

However, if you uncomment the line container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());

, all three decorators will be used for resolution implementation

, which is the desired result (sort :).

class Program
{
    static void Main(string[] args)
    {
        var container = new WindsorContainer();

        container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator1<>)));
        container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator2<>)));
        container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator3<>)));

        //uncomment the line below and watch the magic happen
        //container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());
        container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<implementation>());

        var stringCommandHandler = container.Resolve<ICommandHandler<stringCommand>>();
        var command = new stringCommand();
        stringCommandHandler.Handle(command);

        Console.WriteLine(command.s);
        Console.ReadKey();
    }
}

public interface ICommandHandler<T>
{
    void Handle(T t);
}

public class stringCommand
{
    public string s { get; set; }
}

public abstract class Decorator<T> : ICommandHandler<T>
{
    public abstract void Handle(T t);
};

public class Decorator1<T> : Decorator<T>
    where T : stringCommand
{
    private ICommandHandler<T> _handler;
    public Decorator1(ICommandHandler<T> handler)
    {
        _handler = handler;
    }

    public override void Handle(T t)
    {
        t.s += "Decorator1;";
        _handler.Handle(t);
    }
}

public class Decorator2<T> : Decorator<T>
    where T : stringCommand
{
    private ICommandHandler<T> _handler;
    public Decorator2(ICommandHandler<T> handler)
    {
        _handler = handler;
    }

    public override void Handle(T t)
    {
        t.s += "Decorator2;";
        _handler.Handle(t);
    }
}
public class Decorator3<T> : Decorator<T>
    where T : stringCommand
{
    private ICommandHandler<T> _handler;
    public Decorator3(ICommandHandler<T> handler)
    {
        _handler = handler;
    }

    public override void Handle(T t)
    {
        t.s += "Decorator3;";
        _handler.Handle(t);
    }
}

public class implementation : ICommandHandler<stringCommand>
{
    public void Handle(stringCommand t)
    {
        t.s += "implementation;";
    }
}

      

Why exactly is this happening, is it a Windsor feature that I am not aware of? Is there another way to achieve the same effect? (without thinking)

+1


source to share


1 answer


When Windsor tries to resolve a component, it will first try to resolve a more specific interface. Therefore, when you register Component.For, it will prefer to allow it over the public generic type.

If the same interface is registered multiple times, it will use the first one specified.

So, if you don't define a string, the application will resolve the implementation, as this is the most specific component.



If you uncomment, the line1 decorator is resolved and the magic really starts. The decorator will now start looking for the first registered component that satisfies its constructor, in which case it will be another decorator1 (did you notice your output shows decorator1 2 times?). Which will decide the next registered component and so on until it reaches the actual implementation.

So the only thing I can think of is not registering decorator1 as an open generic, but as a specific type.

Regards, Marwijn.

+1


source







All Articles