Windsor如何为每个解析调用创建一个组件?

时间:2010-07-08 13:09:13

标签: castle-windsor

考虑以下课程:

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 { return _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); }
    }
}

最后我想要完成的事情:

    [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);
    }

如何让Windsor创建一个ITask实例,以便在解析ViewManager时由ViewA和ViewB共享?我尝试了以下但是没有用:

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

                                   })
            .LifeStyle.Transient);

2 个答案:

答案 0 :(得分:0)

  1. 你为什么要这样做?您要做的是将实例绑定到依赖关系树的上下文。也许上下文更广泛,就像网络请求一样?你想这样做的原因是什么。

  2. 有可能,但我知道使用Windsor 2.5这样做的干净方法。以前的版本可能需要一些技巧。

答案 1 :(得分:0)

我找到了一个解决方案,但我希望有人可以建议一个更好的解决方案。请给我一些关于所选解决方案的批评:

    [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);
    }

我做了两件事:

  1. 创建了一个自定义的生活方式管理器,它增加了一种能力,即组件在生活方式范围之外作为瞬态,在单一范围内作为单身。

  2. 创建了一个生活方式范围,我可以用它来指定“上下文边界”。

  3. 有一件事我不喜欢这个解决方案,那就是你必须知道来自呼叫站点的上下文问题。我可以通过将生活方式范围移动到viewmanager来抽象这个,但是viewmanager需要有一个ioc依赖,在测试viewmanager时需要一些额外的存根。