0

我正在尝试了解 Castle.Windsor 中的工作方式如何影响生活方式,但我想我还不明白 :)

所以在下面的测试中,我正在测试以下假设:
1)如果组件绑定到某个东西,它应该在整个依赖层次结构中接收相同的某个实例,这是写在文档中的,并且是可以理解的并且看起来它可以工作。

2)如果组件有多个注册并且第一个注册是绑定的,对于绑定实例它应该像1)一样工作,对于其他实例它应该产生实例,如未绑定注册中所述。这在文档中没有提到,但我看起来也很合乎逻辑。

3) 语法允许链接生活方式,所以通常在单个名称下我应该能够使用多个绑定组件注册组件。它不在下面的测试中,但那是在初始版本中,并没有像我想象的那样工作。

4)(实际问题)如果同一组件具有不同绑定组件的两个注册,它们应该接收不同的实例吗?我看到这个配置有两个问题:

a) Windsor以某种方式无法解决所有依赖项(bound2.DataContext为空)
b)我认为不正确(直观)。bound.DataContextbound2.Service.DataContext

[TestFixture]
public class IocTests
{      
    [Test]
    public void BoundRegistrationsTest()
    {
        var container = new WindsorContainer();
        container.Register(
            Component.For<IDataContext>()
                 .ImplementedBy<DataContext>()
                 .LifestyleBoundTo<BoundContextUser()
                 .Named("IDataContext_BoundContextUser"),
            Component.For<IDataContext>()
                 .ImplementedBy<DataContext>()
                 .LifestyleBoundTo<BoundContextUser2()
                 .Named("IDataContext_BoundContextUser2"),
            Component.For<IDataContext>()
                 .ImplementedBy<DataContext>()
                 .LifestyleTransient(),
            Component.For<BoundContextUser>()
                 .LifestyleTransient(),
            Component.For<BoundContextUser2>()
                 .LifestyleTransient(),
            Component.For<IService>()
                 .ImplementedBy<Service>()
                 .LifeStyleTransient(),
            Component.For<UnboudContextUser>()
                 .LifestyleTransient()
            );

        var bound = container.Resolve<BoundContextUser>();
        var bound2 = container.Resolve<BoundContextUser2>();
        var unbound = container.Resolve<UnboudContextUser>();

        Assert.AreEqual(bound.DataContext, bound.Service.DataContext);
        Assert.AreNotEqual(unbound.DataContext, unbound.Service.DataContext);

        // this fails
        Assert.AreEqual(bound2.DataContext, bound2.Service.DataContext);

        // if bound2.DataContext would not be null, this would fail too
        Assert.AreNotEqual(bound.DataContext, bound2.DataContext);
    }
}

public class BoundContextUser
{
    public IDataContext DataContext { get; set; }
    public IService Service { get; set; }
}

public class BoundContextUser2
{
    public IDataContext DataContext { get; set; }
    public IService Service { get; set; }
}

public interface IService
{
    IDataContext DataContext { get; set; }
}

public class Service : IService
{
    public IDataContext DataContext { get; set; }
}

public class UnboudContextUser
{
    public IDataContext DataContext { get; set; }
    public IService Service { get; set; }        
}

public class DataContext : IDataContext
{

}

public interface IDataContext
{

}

更新:正如 Marwijn 正确注意到的那样,我忘记将生活方式设置为服务,因此 4 b) 不再是实际的,但它仍然不能解决所有属性,如 4 a) 中所述。

4

1 回答 1

1

第一个问题 4b:

由于 Service 是一个单例,因此应用程序中只有 1 个。所以bound.Service == bound2.service永远是真的。第一次解析此服务时,它会在绑定的上下文中解析,因此它将获得绑定的 Datacontext。我会认为这是一个错误配置,因为当绑定的生命周期结束时,在单例服务的生命周期结束之前,服务仍将持有对从容器的角度来看不再存在的对象的引用(Windsor 会在它调用 Dispose 时)实现 IDisposable。

关于其余问题:您似乎将组件与类/接口混为一谈。每个 Component.For 语句注册 1 个组件。向某个接口注册的第一个组件被视为该接口的默认组件(除非被 IsDefault 覆盖)。当一个组件被解析时,它将为每个依赖项尝试创建/获取默认组件。如果这个组件不能被解析(因为它被绑定到不在解析堆栈中的东西)它将停止。

如果你想指定一个组件应该尝试解析一个特定的其他组件,你可以使用 DependsOn 来指定应该解析哪个组件。你可以看到下面的代码。

亲切的问候,马尔维恩。

   var container = new WindsorContainer();
    container.Register(
        Component.For<IDataContext>().ImplementedBy<DataContext>(), // default datacontext
        Component.For<IService>().ImplementedBy<Service>(), // default service.

        Component.For<IDataContext>()
             .ImplementedBy<DataContext>()
             .LifestyleBoundTo<BoundContextUser>()
             .Named("IDataContext_BoundContextUser"),                 
        Component.For<IDataContext>()
             .ImplementedBy<DataContext>()
             .LifestyleBoundTo<BoundContextUser2>()
             .Named("IDataContext_BoundContextUser2"),
        Component.For<BoundContextUser>()
             .LifestyleTransient()
             .DependsOn(
                Dependency.OnComponent(typeof(IDataContext),"IDataContext_BoundContextUser"),
                Dependency.OnComponent(typeof(IService), "IService_BoundContextUser")),
        Component.For<BoundContextUser2>()
             .DependsOn(
                Dependency.OnComponent(typeof(IDataContext), "IDataContext_BoundContextUser2"),
                Dependency.OnComponent(typeof(IService), "IService_BoundContextUser2"))
             .LifestyleTransient(),

        Component.For<IService>()
             .ImplementedBy<Service>()
             .DependsOn(Dependency.OnComponent(typeof(IDataContext),"IDataContext_BoundContextUser"))
             .LifestyleBoundTo<BoundContextUser>()
             .Named("IService_BoundContextUser"),
        Component.For<IService>()
             .ImplementedBy<Service>()
             .DependsOn(Dependency.OnComponent(typeof(IDataContext), "IDataContext_BoundContextUser2"))
             .LifestyleBoundTo<BoundContextUser2>()
             .Named("IService_BoundContextUser2"),

        Component.For<UnboudContextUser>()
             .LifestyleTransient()
        );

    var bound = container.Resolve<BoundContextUser>();
    var bound2 = container.Resolve<BoundContextUser2>();
    var unbound = container.Resolve<UnboudContextUser>();

    Assert.AreEqual(bound.DataContext, bound.Service.DataContext);
    Assert.AreEqual(unbound.DataContext, unbound.Service.DataContext);
    Assert.AreEqual(bound2.DataContext, bound2.Service.DataContext);
    Assert.AreNotEqual(bound.DataContext, bound2.DataContext);
于 2013-05-02T13:35:47.247 回答