Castle.Windsor:来自一个类型工厂的组件的可选分辨率 [英] Castle.Windsor: optional resolution of component from a typed factory
问题描述
IHandler< Message>
,其中消息是查询)。 然而,在某些情况下,在处理程序可以执行之前还会有一个;该消息必须用来自其他地方的数据完成。我想要的是检查是否存在针对我的消息类型的注射器,如果存在注射器,则运行它。
IInjector< ;消息> Injector = InjectorFactory.RetrieveInjector< Message>();
if(Injector!= null)
{
Logger.InfoFormat(IInjector< {0}&OK),input.GetType()。Name);
Injector.InjectCode(输入,数据来自其他地方);
}
背后的原因是在未来的某个时候有人可能会创建一个插件一个 IInjector< Message>
,我想在未来的时间选择它;但是目前它不存在。
当没有找到一个组件而不是抛出一个 ComponentNotFoundException
?
编辑
与@Steven我会回答我自己的问题,以编译什么导致我的解决方案和我发现的决议。首先让我们重述一下这个问题。
我有一个WCF服务基本上遵循KrzysztofKoźmic在这篇文章
但是,在调用处理程序之前,我希望有一个选项操作,如果需要,传入的消息将被修改。
private static void DoActualWork< T>(T命令)
{
IInjector< T>注射器=注射器工件。注射器T();
if(Injector!= null){Injector.InjectThings(command,); }
var handlers = factory.GetHandlersForCommand(command);
foreach(处理程序中的var handler)
{
handler.Execute();
}
}
我与injectFactory有问题;当我要求它找到一个不存在的组件时,它会抛出一个 ComponentNotFoundException
。我想要的是工厂认识到没有组件,只是返回null。
史蒂文指出两个探索解决方案的方法:
- 不要检查null,而是使用空对象模式
- 包含
IHandler< T>
与装饰器,并在装饰器中注入IInjector
第二个选项是不可取的,因为它将加载处理程序他们不必了解的责任。理想情况下,我应该将这种注入行为转移到自己的独立拦截器中,让它完全在那里生存,而不需要任何其他代码知道它。我可以稍后这样做。
第一点是要走的路。空对象模式减少了我的方法的复杂性,使其比使用空检查更清晰。所有我要做的是创建一个 NopInjector
类,并将其声明为工厂的默认值。
strong>不要尝试根据基础对象创建注射器:
public class NopInjector:IInjector<对象>
{
public void InjectStuff(object target,string stuff){}
}
相反,创建一个通用注入器并将其注册为一个打开的通用组件
public class NopInjector< T> :IInjector< T>
{
public void InjectStuff(T target,string stuff){}
}
//注册
_container.Register(
组件.For(typeof(IInjector?))
.ImplementedBy(typeof(NopInjector?))
.IsDefault());
_container.Register(
Classes
.FromAssemblyInThisApplication()
.BasedOn(typeof(IInjector?))
.WithService.AllInterfaces());
现在,如果Castle.Windsor可以解析特定的 IInjector< Command> code>它会,否则它会返回
NopInjector
。没有更多的空检查:
private static void DoActualWork< T>(T命令)
{
injectFactory .GetInjector< T>()。InjectThings(command,);
//调用处理程序...
}
I have a WCF service setup with Castle.Windsor; messages arrive to a dispatcher that send them to the right component (basically a IHandler<Message>
with message being a query).
However in some cases there is one additional before the handler can act; the message must be completed with data coming from someplace else. What i want is to check whether there exists an injector for the type of my message and if one exists, run it.
IInjector<Message> Injector = InjectorFactory.RetrieveInjector<Message>();
if (Injector != null)
{
Logger.InfoFormat("IInjector<{0}> OK", input.GetType().Name);
Injector.InjectCode(input, "Data coming from somewhere else");
}
The reasoning behind this is that at some future point somebody may create a plugin with a IInjector<Message>
and I want to pick it at a future time; but at the moment it doesn't exist.
Is it possible to have a typed factory returning null when a component is not found instead of throwing a ComponentNotFoundException
?
EDIT
As discussed with @Steven I will be answering my own question in order to compile what lead me to the solution and the resolution i found. First let's restate the problem
I have a WCF service basically following the structure described by Krzysztof Koźmic in this article
However, before calling the handlers i wanted to have an optionnal operation where the incoming message would be modified if needed.
private static void DoActualWork<T>(T command)
{
IInjector<T> Injector = injectorFactory.GetInjector<T>();
if (Injector != null) { Injector.InjectThings(command, ""); }
var handlers = factory.GetHandlersForCommand(command);
foreach (var handler in handlers)
{
handler.Execute();
}
}
I was having a problem with the injectorFactory; when i asked it to find a non-existing component it would throw a ComponentNotFoundException
. What i would have liked is for the factory to recognize there was no component and simply return a null.
Steven points out two ways to explore to reach a solution :
- Don't check for null, rather use a Null Object Pattern
- Wrap the
IHandler<T>
with a decorator and inject the IInjector in the decorator
The second option was not desirable since it would have loaded the handlers with a responsibility they didn't have to know about. Ideally I should move this injection behavior into its own independent interceptor and let it live entirely there without any other code knowing about it. I may do that later.
The first point though is the way to go. Null Object Pattern decreases the complexity of my method and leaves it much clearer than with a null check. All i have to do is create a NopInjector
class and declare it as the default value for the factory.
Don't try to create an injector depending on a base object:
public class NopInjector : IInjector<object>
{
public void InjectStuff(object target, string stuff) { }
}
Rather create a generic injector and register it as an open generic component
public class NopInjector<T> : IInjector<T>
{
public void InjectStuff(T target, string stuff) { }
}
// registration
_container.Register(
Component.For(typeof(IInjector<>))
.ImplementedBy(typeof(NopInjector<>))
.IsDefault());
_container.Register(
Classes
.FromAssemblyInThisApplication()
.BasedOn(typeof(IInjector<>))
.WithService.AllInterfaces());
Now if Castle.Windsor can resolve a specific IInjector<Command>
it will, else it will return the NopInjector
. No more null check:
private static void DoActualWork<T>(T command)
{
injectorFactory.GetInjector<T>().InjectThings(command, "");
// calling handlers...
}
这篇关于Castle.Windsor:来自一个类型工厂的组件的可选分辨率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!