我试图了解Castle.Windsor的生活方式是如何运作的,我想我还没有得到它:)
因此,在下面的测试中,我按照以下假设进行测试:
1)如果组件绑定到某个东西,它应该在整个依赖关系层次结构中接收相同的事物实例,这是在文档中编写的,并且是可以理解的并且看起来很有效。
2)如果组件具有多个注册并且第一次注册被绑定,则对于绑定实例,它应该如1)中那样工作,对于其他实例,它应该生成非绑定注册中描述的实例。文档中没有提到这一点,但我看起来也很符合逻辑。
3)语法允许链接生活方式,因此通常在单个名称下我应该能够注册具有多个绑定组件的组件。它不在下面的测试中,但那是初始版本,并没有像我想象的那样工作。
4)(实际问题)如果对于具有不同绑定组件的相同组件有两个注册,它们应该接收不同的实例?我在这里看到了这个配置的两个问题:
a)Windsor不能解决所有依赖关系(bound2.DataContext
为空)
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正确地注意到的那样,我已经忘记了将生活方式设置为服务,因此4 b)不再是实际的,但仍然没有解决所有属性,如4 a)中所述。
答案 0 :(得分:1)
第一个问题4b:
由于Service是单例,因此应用程序中只有1。所以bound.Service == bound2.service总是如此。第一次解析此服务时,它将在绑定的上下文中解析,因此它将获得绑定的Datacontext。 我认为这是一个配置错误,因为当绑定的生命周期结束时,在单例服务的生命周期之前,服务仍将保持对一个对象的引用,这个对象从容器的角度来看已经不再存在(Windsor将在它上面调用Dispose)实现IDisposable。
关于其他问题:您似乎将组件与类/接口混淆。每个Component.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);