Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
351 views
in Technique[技术] by (71.8m points)

registering open generic decorators for typed implementations in castle windsor

While trying to coerce Windsor into wrapping an implementation with a random number of decorators, i've stumbled upon the following:

i have 3 decorators and an implementation all using the same interface.

if you run this code, windsor resolves icommandhandler<stringcommand> as implementation, which, as far as i can tell, is expected behaviour, because the typed implementation can not be registered with the open typed decorators.

However, if you uncomment the line container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());, all three decorators will be used to resolve implementation, which is the desired result (sort of : ).

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 this a feature of windsor that i am not aware of? Is there perhaps a different way to achieve the same effect? (without resorting to reflection)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

When windsor tries to resolve a component it will first try to resolve the more specific interface. So when you register Component.For it will prefer to resolve this over an open generic type.

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

So if you don't uncommment the line your application will resolve implementation since this is the most specific component.

If you do uncomment the line decorator1 will be resolved and indeed the magic starts. The decorator will now start looking for the first registered component that satisfies it's constructor, in this case that would be decorator1 again (you did notice that your output show decorator1 2 times ?). Which will the resolve the next registered component and so on till it comes to the actual implementation.

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

Kind regards, Marwijn.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...