除了注入 Castle Windsor 类型的工厂之外,还有其他选择吗?

Any alternative to injecting Castle Windsor typed factories?

我的大部分组件都是使用基于代码的(流畅的)方法注册的,但有一个特定组件需要在运行时以不同方式解析。这是接口和几个具体实现:-

public interface ICommsService ...

public class SerialCommsService : ICommsService ...

public class TcpCommsService : ICommsService ...

我们的一些用户将需要串口服务,而另一些用户将需要 TCP 服务。我当前的解决方案(顺便说一句,可行)是使用类型化工厂和自定义组件选择器——后者读取 app.config 设置以确定类型化工厂将解析哪个实现和 return。

首先是类型工厂(这没什么特别的):-

public interface ICommsServiceFactory
{
    ICommsService Create();
    void Release(ICommsService component);
}

接下来,自定义组件选择器,它从 app.config 中读取完全限定的类型名称(例如 "MyApp.SomeNamespace.TcpCommsService"):-

public class CommsFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
    protected override string GetComponentName(MethodInfo method, object[] arguments)
    {
        return ConfigurationManager.AppSettings["commsServiceType"];
    }
}

然后是注册的东西:-

var container = new WindsorContainer();

container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactoryComponentSelector>()
         .ImplementedBy<CommsFactoryComponentSelector>());
container.Register(Component.For<ICommsFactory>()
         .AsFactory(o => o.SelectedWith<CommsFactoryComponentSelector>()));

container.Register(Component.For<ICommsService>()
         .ImplementedBy<SerialCommsService>().LifeStyle.Singleton);
container.Register(Component.For<ICommsService>()
         .ImplementedBy<TcpCommsService>().LifeStyle.Singleton);

最后,一个依赖于 ICommsService 的示例 class:-

public class Test
{
    public Test(ICommsFactory commsFactory)
    {
        var commsService = commsFactory.Create();
        ...
    }
}

如前所述,上述解决方案 确实 有效,但我不喜欢必须注入工厂。如果我可以只注入一个 ICommsService,然后让某个地方找出要解析和注入哪个实现,那会更直观——类似于我现在正在做的,但早些时候在 Windsor 的 "resolving pipeline" 中。这样的事情可能吗?

您可以在此处使用 UsingFactoryMethod

container.Register(Component.For<ICommsService>().UsingFactoryMethod(kernel => kernel.Resolve<ICommsServiceFactory>().Create()));

您现在可以将 ICommsService 注入任何 class。 ICommsServiceFactory现在可以是一个简单的界面了:

interface ICommsServiceFactory
{
    ICommsService Create(); 
}