我试图了解如何使用TypedFactoryFacility
创建一个抽象工厂,我让它在基础层面上工作,但是我不完全理解如何使用运行时来扩展它依赖
假设我有一个需要在运行时创建的服务:
public interface IRuntimeService {
void DoThing();
}
具有以下实现
public class RuntimeService : IRuntimeService {
public void DoThing() {
// Do some work
}
}
要创建我的IRuntimeService
,我已经创建了一个抽象工厂
public interface IRuntimeServiceFactory {
IRuntimeService CreateService();
}
在我的Castle安装程序中,我使用TypedFactoryFacility
注册我的班级和抽象工厂。
public class TypeInstaller : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IRuntimeService>().ImplementedBy<RuntimeService>());
container.Register(Component.For<IRuntimeServiceFactory>().AsFactory());
}
然后在我将要使用该服务的类中,我可以使用工厂在运行时创建新的服务实例。
var myService = m_ServiceFactory.CreateService();
以上所有内容都非常有效,但是当我的RuntimeService
类需要注入一个包含运行时参数的依赖链本身时,我遇到了问题。
要扩展上面的示例,假设我有一个新的运行时依赖
public interface IRuntimeDependency {
void DoWork();
}
由一个通过构造函数
获取运行时字符串值的类实现public class RuntimeDependency : IRuntimeDependency {
private readonly string m_Param;
public RuntimeDependency(string param) {
m_Param = param;
}
public void DoWork() {
// Do work involving the param
}
}
以前定义的服务类现在需要对依赖项的引用
public class RuntimeService : IRuntimeService {
private readonly IRuntimeDependency m_Dep;
public RuntimeService(IRuntimeDependency dep) {
m_Dep = dep;
}
public void DoThing() {
// Do some work involving the dependency
m_Dep.DoWork();
}
}
我现在如何使用TypedFactoryFacility
创建服务实例?
我希望能够将我的工厂方法更改为
IRuntimeService CreateService(string param);
但是Windsor抛出错误&#39;无法解析参数&#39; param&#39;的非可选依赖项。输入&#39; System.String&#39;。
如果我给它一个字符串,Windsor知道如何创建IRuntimeDependency
,如果我给它依赖,它知道如何创建IRuntimeService
,那么为什么不能直接创建它带有字符串参数的IRuntimeService
?
我可以通过两种不同的工厂方法来实现它的工作
IRuntimeService CreateService(IRuntimeDependency dep);
IRuntimeDependency CreateDependency(string param);
并手动创建依赖项
var dep = m_ServiceFactory.CreateDependency(param);
var myService = m_ServiceFactory.CreateService(dep );
^^^这个工作,但是使用容器的重点是它将负责为我组装新对象。这是一个只涉及一个依赖关系的相对简单的例子,但它很容易失控,使用更复杂的对象图。
我当然可以创建自己的工厂实现,但这也会使使用TypedFactoryFacility
的好处无效,而FactoryComponentSelector
应该为您创建抽象工厂实现。我很难相信这个问题不是现有解决方案,但Windsor示例不包含任何链式运行时依赖项。
我不认为使用RuntimeService
是正确的方法,因为只有一条可能的路径来创建<label id="internet_ipaddr" class="label_s1"></label>
实例。它应该能够自动解决。
答案 0 :(得分:2)
在许多或大多数情况下,容器解析的对象取决于容器也解析的其他接口的实现。因此,只要所有接口都已注册实现,容器就可以解析整个依赖关系链。
但在这种情况下RuntimeDependency
取决于字符串,而不是容器可以解析的字符串。
public RuntimeDependency(string param) {
m_Param = param;
}
在这种情况下,您可以使用DependsOn
方法显式提供值来实现该依赖关系。
container.Register(Component.For<IRuntimeDependency, RuntimeDependency>()
.DependsOn(Dependency.OnValue("param","whatEverTheValueIs")));
当然,这个价值可以来自配置或其他任何地方。我在SQL连接字符串中使用了很多。
答案 1 :(得分:1)
可以使用DynamicParameters。
container.Register(Component.For<IRuntimeService>()
.ImplementedBy<RuntimeService>()
.LifestyleTransient()
.DynamicParameters((k, d) => {
d["dep"] = new RuntimeDependency((string)d["param"]);
}));
请记住,字典键必须与CreateService
方法和RuntimeService
构造函数中的参数名称匹配。
编辑:如果您打算在每次调用工厂方法时创建新实例,也应该将其设为LifestyleTransient。 (默认为单身)
答案 2 :(得分:0)