开发者

How can Windsor create one component for each resolve invocation?

Consider the following classes:

public interface IView
{
    /// <summary>
    /// Ignore this (its only for the assertion)
    /// </summary>
    ITask Task { get; }
}

public class ViewA : IView
{
    private readonly ITask _task;

    public ViewA(ITask task)
    {
        _task = task;
    }

    public ITask Task
    {
        get { r开发者_运维知识库eturn _task; }
    }
}
public class ViewB : IView
{
    private readonly ITask _task;

    public ViewB(ITask task)
    {
        _task = task;
    }

    public ITask Task
    {
        get { return _task; }
    }
}

public class ViewManager
{
    private readonly List<IView> _views;

    public ViewManager(IView[] views)
    {
        _views = new List<IView>(views);
    }

    public ReadOnlyCollection<IView> Views
    {
        get { return new ReadOnlyCollection<IView>(_views); }
    }
}

And finally what I am trying to accomplish:

    [Fact]
    public void Configure_TwoServicesWithDependencyToTransientComponent_BothShareComponent()
    {
        // arrange
        var windsorContainer = new WindsorContainer();

        windsorContainer.Kernel.Resolver.AddSubResolver(new ArrayResolver(windsorContainer.Kernel));

        windsorContainer.Register(Component.For<ITask>()
            .ImplementedBy<TaskWithNoDependencies>()
            .Named("task")
            .LifeStyle.Transient);

        windsorContainer.Register(Component.For<IView>().ImplementedBy<ViewA>().LifeStyle.Transient);
        windsorContainer.Register(Component.For<IView>().ImplementedBy<ViewB>().LifeStyle.Transient);

        windsorContainer.Register(Component.For<ViewManager>()
            .LifeStyle.Transient);

        // act
        ViewManager service = windsorContainer.Resolve<ViewManager>();

        // assert
        Assert.Same(service.Views[0].Task, service.Views[1].Task);
    }

How can I make Windsor create an instance of ITask so thats its shared by ViewA and ViewB when resolving ViewManager? I tried the following but it did not work:

        windsorContainer.Register(Component.For<ViewManager>()
            .DynamicParameters((k, d) =>
                                   {
                                       d["task"] = k.Resolve<ITask>();

                                   })
            .LifeStyle.Transient);


  1. Why do you want to do it like this? What you're trying to do is to bind an instance to a context of dependency tree. Perhaps the context is broader, like a web request? What's the reason why you want to do it like this.

  2. It is possible, but I know clean way of doing this with Windsor 2.5. Previous version probably requires some trickery.


I found a solution, but I'm hoping that someone can suggest a better one. Please give me some critic on the selected solution:

    [Fact]
    public void Configure_TwoServicesWithDependencyToTransientComponent_BothShareComponent()
    {
        // arrange
        var windsorContainer = new WindsorContainer();

        windsorContainer.Kernel.Resolver.AddSubResolver(new ArrayResolver(windsorContainer.Kernel));

        windsorContainer.Register(Component.For<ITask>().ImplementedBy<TaskWithNoDependencies>().LifeStyle.Custom(typeof(PerScopeOrTransientLifestyleManager)));

        windsorContainer.Register(Component.For<IView>().ImplementedBy<ViewA>().LifeStyle.Transient);
        windsorContainer.Register(Component.For<IView>().ImplementedBy<ViewB>().LifeStyle.Transient);

        windsorContainer.Register(Component.For<ViewManager>()
            .LifeStyle.Transient);

        // act
        ViewManager service;

        using (new LifeStyleScope())
        {
            service = windsorContainer.Resolve<ViewManager>();
        }

        // assert
        Assert.Same(service.Views[0].Task, service.Views[1].Task);
    }

I did two things:

  1. Created a custom lifestyle manager which added the ability to say that components would act as transient outside of a lifestyle scope and as a singleton within one.

  2. Created a lifestyle scope which I can use to specify a "context-boundary".

There is one thing I don't like about this solution and that is the fact that you have to know about the context-issue from the call-site. I could abstract this by moving the lifestyle scope into the viewmanager, but then the viewmanager needs to have an ioc dependency which will require some extra stubbing when testing the viewmanager.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜