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