C# 温莎城堡抽象工厂

C# 温莎城堡抽象工厂,c#,dependency-injection,castle-windsor,C#,Dependency Injection,Castle Windsor,我试图理解如何使用TypedFactoryFacility创建抽象工厂,我让它在一个基本级别上工作,但是我不完全理解如何使用运行时依赖项来扩展它 假设我有一个需要在运行时创建的服务: public interface IRuntimeService { void DoThing(); } 通过以下实现 public class RuntimeService : IRuntimeService { public void DoThing() { // Do some work

我试图理解如何使用
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());
  }

上面的一切都可以完美地工作,但是当我的
RuntimeService
类需要注入包含运行时参数的依赖链时,我遇到了一个问题

为了扩展上面的示例,假设我有一个新的运行时依赖项

public interface IRuntimeDependency {
  void DoWork();
}
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();
  }
}
由通过构造函数获取运行时字符串值的类实现

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 interface IRuntimeDependency {
  void DoWork();
}
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抛出错误“无法解析参数“param”类型“System.String”的非可选依赖项”

如果我给它一个字符串,温莎知道如何创建
IRuntimeDependency
,如果我给它一个依赖项,温莎知道如何创建
IRuntimeService
,那么为什么它不能直接用字符串参数创建
IRuntimeService

我可以通过两种不同的工厂方法来实现

IRuntimeService CreateService(IRuntimeDependency dep);
IRuntimeDependency CreateDependency(string param);
并手动创建依赖项

var dep = m_ServiceFactory.CreateDependency(param);
var myService = m_ServiceFactory.CreateService(dep );
^^^^这很有效,但使用容器的全部意义在于它可以为我组装新对象。这是一个只涉及一个依赖项的相对简单的示例,但如果使用更复杂的对象图,它很容易失控

当然,我可以创建自己的工厂实现,但这也抵消了使用
TypedFactoryFacility
的好处,它应该为您创建抽象工厂实现。我很难相信这个问题没有现成的解决方案,但是Windsor示例不包含任何链式的运行时依赖项


我认为使用
FactoryComponentSelector
不是正确的方法,因为创建
RuntimeService
实例只有一种可能的路径。它应该能够自动解析。

在许多或大多数情况下,容器解析的对象取决于容器解析的其他接口的实现。因此,只要所有接口都注册了实现,容器就可以解析整个依赖链

但是在本例中,
RuntimeDependency
依赖于字符串,而该字符串不是容器可以解析的

public RuntimeDependency(string param) {
    m_Param = param;
}
在这种情况下,您可以使用
DependsOn
方法显式提供一个值来实现该依赖关系

container.Register(Component.For<IRuntimeDependency, RuntimeDependency>()
    .DependsOn(Dependency.OnValue("param","whatEverTheValueIs")));
container.Register(Component.For())
.DependsOn(Dependency.OnValue(“param”,“whatEverTheValueIs”));

当然,该值可以来自配置或其他任何地方。我经常在SQL连接字符串中使用它。

在许多或大多数情况下,容器解析的对象依赖于容器解析的其他接口的实现。因此,只要所有接口都注册了实现,容器就可以解析整个依赖链

但是在本例中,
RuntimeDependency
依赖于字符串,而该字符串不是容器可以解析的

public RuntimeDependency(string param) {
    m_Param = param;
}
在这种情况下,您可以使用
DependsOn
方法显式提供一个值来实现该依赖关系

container.Register(Component.For<IRuntimeDependency, RuntimeDependency>()
    .DependsOn(Dependency.OnValue("param","whatEverTheValueIs")));
container.Register(Component.For())
.DependsOn(Dependency.OnValue(“param”,“whatEverTheValueIs”));

当然,该值可以来自配置或其他任何地方。我经常在SQL连接字符串中使用这一点。

似乎我所要求的是设计上不可能实现的

看到这个答案了吗


看来我所要求的是设计上不可能的

看到这个答案了吗

可以使用

container.Register(Component.For())
.由()实施
.生活方式
.动态参数((k,d)=>{
d[“dep”]=新的RuntimeDependency((字符串)d[“param”]);
}));
请记住,字典键必须与
CreateService
方法和
RuntimeService
构造函数中的参数名匹配

编辑:如果每次调用factory方法时都要创建一个新实例,那么也应该这样做。(默认为单例)

可以使用

container.Register(Component.For())
.由()实施
.生活方式
.动态参数((k,d)=>{
d[“dep”]=新的RuntimeDependency((字符串)d[“param”]);
}));
请记住,字典键必须与
CreateService
方法和
RuntimeService
构造函数中的参数名匹配


编辑:如果每次调用factory方法时都要创建一个新实例,那么也应该这样做。(默认值为singleton)

太好了,我认为这让我走上了正确的道路,但我的参数不是静态值,而是在运行时传入的参数。如何将传入工厂的值映射到
RuntimeDependency
构造函数?字符串来自何处?任何依赖于物体的东西都不能通过它,所以它一定是环保的。也许你需要的不是一个字符串,而是另一个对象,当你需要它时,它提供你需要的字符串。它不是环境的,它是一个从文件加载的运行时参数