如果同一个组件有两个不同绑定组件的注册,它们应该接收不同的实例
本文关键字:组件 实例 注册 同一个 两个 绑定 如果 | 更新日期: 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);