解决 Castle Windsor 中 "Super interface" 的实施问题
Resolving implementation of "Super interface" in Castle Windsor
也许甚至不可能,但这是我的需要。
我有一个键映射器的通用实现,以及一个能够生成此类映射器的工厂 class
public class KeyMapperFactory
{
IKeyMapper<TInternalKey, TExternalKey> GetMapper<TInternalKey, TExternalKey>(MapperConfig config)
}
现在我想在应用程序中有 "speak clear" 的接口,所以我会在我的应用程序中创建另一个空接口,如下所示
public interface IMapCompanyToPayrollCompany : IKeyMapper<CompanyId, PayrollCompanyId>
{
}
我是否有机会以这种(错误的)方式使用 CastleWindsor 创建 "on the fly" IMapCompanyToPayrollCompany
的实现?
var mapperConfig = MapperConfig {
...
};
var keyMapperFactory = new KeyMapperFactory();
var container = new WindsorContainer();
container.Register(
Component
.For<IMapCompanyToPayrollCompany>()
.UsingFactoryMethod(kernel => (IMapCompanyToPayrollCompany)keyMapperFactory.GetMapper<CompanyId, PayrollCompanyId>(mapperConfig)
);
我找到了使用 Castle 的 DynamicProxies 的解决方案
// I developed an extension method on the IWindsorContainer
public static void RegisterMapper<TSpeakingInterface, TInternal, TExternal>(this IWindsorContainer container, MapperConfig config)
where TSpeakingInterface : IKeyMapper<TInternal, TExternal>
{
container.Register(
Component
.For<TSpeakingInterface>()
.UsingFactoryMethod(() => {
var generator = new ProxyGenerator(); // <--Documentation recommend this to be a Singleton for performance and memory reason ...
var keyMapperFactory = new KeyMapperFactory();
var mapper = keyMapperFactory.GetMapper<TInternal, TExternal>(config);
var interceptor = new KeyMapperInterceptor<TInternal, TExternal>(mapper);
// see: https://github.com/castleproject/Windsor/issues/224
var nullProxy = generator.CreateInterfaceProxyWithoutTarget<TSpeakingInterface>();
return generator.CreateInterfaceProxyWithTarget(nullProxy, interceptor);
})
);
}
// Now I can register a mapper this way:
var container = new WindsorContainer();
var config = new MapperConfig {
[...] // mapper config stuff here
}
container.RegisterMapper<IMapCompanyToPayrollCompany, CompanyId, PayrollCompanyId>(config);
拦截器就这么简单
public class KeyMapperInterceptor<TInternal, TExternal> : IInterceptor
{
private readonly IKeyMapper<TInternal, TExternal> realMapper;
public KeyMapperInterceptor(IKeyMapper<TInternal, TExternal> realMapper)
{
this.realMapper = realMapper;
}
public void Intercept(IInvocation invocation)
{
// We simply call the corresponding method on the realMapper
var method = invocation.Method;
invocation.ReturnValue = method.Invoke(realMapper, invocation.Arguments);
}
}
...而且有效!
当然,IMapCompanyToPayrollCompany
中不允许使用其他方法或属性,因为拦截器将尝试 execute/access 在“realMapper”上使用它们,而“realMapper”对此一无所知!
也许甚至不可能,但这是我的需要。
我有一个键映射器的通用实现,以及一个能够生成此类映射器的工厂 class
public class KeyMapperFactory
{
IKeyMapper<TInternalKey, TExternalKey> GetMapper<TInternalKey, TExternalKey>(MapperConfig config)
}
现在我想在应用程序中有 "speak clear" 的接口,所以我会在我的应用程序中创建另一个空接口,如下所示
public interface IMapCompanyToPayrollCompany : IKeyMapper<CompanyId, PayrollCompanyId>
{
}
我是否有机会以这种(错误的)方式使用 CastleWindsor 创建 "on the fly" IMapCompanyToPayrollCompany
的实现?
var mapperConfig = MapperConfig {
...
};
var keyMapperFactory = new KeyMapperFactory();
var container = new WindsorContainer();
container.Register(
Component
.For<IMapCompanyToPayrollCompany>()
.UsingFactoryMethod(kernel => (IMapCompanyToPayrollCompany)keyMapperFactory.GetMapper<CompanyId, PayrollCompanyId>(mapperConfig)
);
我找到了使用 Castle 的 DynamicProxies 的解决方案
// I developed an extension method on the IWindsorContainer
public static void RegisterMapper<TSpeakingInterface, TInternal, TExternal>(this IWindsorContainer container, MapperConfig config)
where TSpeakingInterface : IKeyMapper<TInternal, TExternal>
{
container.Register(
Component
.For<TSpeakingInterface>()
.UsingFactoryMethod(() => {
var generator = new ProxyGenerator(); // <--Documentation recommend this to be a Singleton for performance and memory reason ...
var keyMapperFactory = new KeyMapperFactory();
var mapper = keyMapperFactory.GetMapper<TInternal, TExternal>(config);
var interceptor = new KeyMapperInterceptor<TInternal, TExternal>(mapper);
// see: https://github.com/castleproject/Windsor/issues/224
var nullProxy = generator.CreateInterfaceProxyWithoutTarget<TSpeakingInterface>();
return generator.CreateInterfaceProxyWithTarget(nullProxy, interceptor);
})
);
}
// Now I can register a mapper this way:
var container = new WindsorContainer();
var config = new MapperConfig {
[...] // mapper config stuff here
}
container.RegisterMapper<IMapCompanyToPayrollCompany, CompanyId, PayrollCompanyId>(config);
拦截器就这么简单
public class KeyMapperInterceptor<TInternal, TExternal> : IInterceptor
{
private readonly IKeyMapper<TInternal, TExternal> realMapper;
public KeyMapperInterceptor(IKeyMapper<TInternal, TExternal> realMapper)
{
this.realMapper = realMapper;
}
public void Intercept(IInvocation invocation)
{
// We simply call the corresponding method on the realMapper
var method = invocation.Method;
invocation.ReturnValue = method.Invoke(realMapper, invocation.Arguments);
}
}
...而且有效!
当然,IMapCompanyToPayrollCompany
中不允许使用其他方法或属性,因为拦截器将尝试 execute/access 在“realMapper”上使用它们,而“realMapper”对此一无所知!