如果同一个组件有两个不同绑定组件的注册,它们应该接收不同的实例

本文关键字:组件 实例 注册 同一个 两个 绑定 如果 | 更新日期: 2023-09-27 18:11:41

我想了解工作是如何影响Castle的生活方式的。温莎和我想我还不明白:)

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

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

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

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

a)温莎不能解析所有依赖项(bound2.DataContext为null)
b) bound.DataContext等于bound2.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正确注意到的那样,我忘记将生活方式设置为服务,所以4b)不再是实际的,但它仍然不能解析所有属性,如4a)所述。

如果同一个组件有两个不同绑定组件的注册,它们应该接收不同的实例

第一个问题4:

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

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

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

亲切的问候,Marwijn。

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