Generics 如何使Castle windsor解析带有约束的泛型? 使用系统; 使用温莎城堡; 使用Castle.MicroKernel.Registration; 运用系统反思; 使用Castle.MicroKernel.Resolvers.SpecializedResolver; 名称空间温莎 { 类主类 { 公共静态void Main(字符串[]args) { var container=新的WindsorContainer(); 容器寄存器(Component.For(typeof(IIface))。由(typeof(handlerimp))实现; //容器寄存器(Component.For(typeof(IIface))。由(typeof(Impl2))实现; container.Kernel.Resolver.AddSubResolver(新的ArrayResolver(container.Kernel)); var normal=container.ResolveAll(); var ex=container.ResolveAll(); //var qwe=newhandlerepl(); 控制台。WriteLine(“你好,世界!”); } } 公共类基类{} 公共类存根{} 公共接口附加 { } 公共接口IIface,其中T1:Base,其中T2:class { T1命令{get;set;} } 公共类句柄impl:iFace其中T1:Base,AdditionalIface其中T2:class { 公共T1命令{get;set;} } 公共类Impl1:基 { } 公共类Impl2:基本类,附加类 { } }
那么,现在如果我这样做:Generics 如何使Castle windsor解析带有约束的泛型? 使用系统; 使用温莎城堡; 使用Castle.MicroKernel.Registration; 运用系统反思; 使用Castle.MicroKernel.Resolvers.SpecializedResolver; 名称空间温莎 { 类主类 { 公共静态void Main(字符串[]args) { var container=新的WindsorContainer(); 容器寄存器(Component.For(typeof(IIface))。由(typeof(handlerimp))实现; //容器寄存器(Component.For(typeof(IIface))。由(typeof(Impl2))实现; container.Kernel.Resolver.AddSubResolver(新的ArrayResolver(container.Kernel)); var normal=container.ResolveAll(); var ex=container.ResolveAll(); //var qwe=newhandlerepl(); 控制台。WriteLine(“你好,世界!”); } } 公共类基类{} 公共类存根{} 公共接口附加 { } 公共接口IIface,其中T1:Base,其中T2:class { T1命令{get;set;} } 公共类句柄impl:iFace其中T1:Base,AdditionalIface其中T2:class { 公共T1命令{get;set;} } 公共类Impl1:基 { } 公共类Impl2:基本类,附加类 { } },generics,castle-windsor,Generics,Castle Windsor,那么,现在如果我这样做: using System; using Castle.Windsor; using Castle.MicroKernel.Registration; using System.Reflection; using Castle.MicroKernel.Resolvers.SpecializedResolvers; namespace Windsor { class MainClass { public static void Main (
using System;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using System.Reflection;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
namespace Windsor
{
class MainClass
{
public static void Main (string[] args)
{
var container = new WindsorContainer ();
container.Register (Component.For (typeof(IIface<, >)).ImplementedBy (typeof(HandlerImpl<, >)));
//container.Register (Component.For (typeof(IIface<, >)).ImplementedBy(typeof(Impl2)));
container.Kernel.Resolver.AddSubResolver (new ArrayResolver (container.Kernel));
var normal = container.ResolveAll<IIface<Impl2, Stub>> ();
var ex = container.ResolveAll<IIface<Impl1, Stub>> ();
//var qwe = new HandlerImpl<Impl1, Stub> ();
Console.WriteLine("Hello World!");
}
}
public class Base {}
public class Stub {}
public interface AdditionalIface
{
}
public interface IIface<T1, T2> where T1 : Base where T2 : class
{
T1 Command { get; set; }
}
public class HandlerImpl<T1, T2> : IIface<T1, T2> where T1 : Base, AdditionalIface where T2 : class
{
public T1 Command { get; set; }
}
public class Impl1 : Base
{
}
public class Impl2 : Base, AdditionalIface
{
}
}
var normal=container.ResolveAll();//这样行吗
var ex=container.ResolveAll();//这会引发关于未满填充约束的异常
//相反,我希望它只显示没有解决的实现
有什么方法可以让它按我所希望的那样工作吗?实际上,这似乎是温莎代码中的一个bug 更新:
现在它已修复如果您正在正常注入内容(即使用ArrayResolver,而不是直接调用
ResolveAll()
),则可以使用自定义数组解析器解决此问题,仅用于此类型(或有此问题的类型):
在标准ArrayResolver之前注册它:
public class CustomArrayResolver : ISubDependencyResolver {
private readonly IKernel kernel;
private readonly Type serviceTypeDefinition;
public CustomArrayResolver(IKernel kernel, Type serviceTypeDefinition) {
this.kernel = kernel;
this.serviceTypeDefinition = serviceTypeDefinition;
}
private bool MatchesConstraints(Type service, Type impl) {
try {
impl.MakeGenericType(service.GetGenericArguments());
return true;
} catch (ArgumentException) {
return false;
}
}
public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency) {
var service = dependency.TargetType.GetElementType();
var handlers = kernel.GetAssignableHandlers(service);
var components = handlers
.Where(h => h.CurrentState == HandlerState.Valid)
.Where(h => MatchesConstraints(service, h.ComponentModel.Implementation))
.Select(h => h.Resolve(context, contextHandlerResolver, model, dependency))
.ToArray();
var r = Array.CreateInstance(service, components.Length);
components.CopyTo(r, 0);
return r;
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency) {
return dependency.TargetType != null &&
dependency.TargetType.IsArray &&
kernel.HasComponent(dependency.TargetType.GetElementType()) &&
dependency.TargetType.GetElementType().IsGenericType &&
dependency.TargetType.GetElementType().GetGenericTypeDefinition() == serviceTypeDefinition;
}
}
container.Kernel.Resolver.AddSubResolver(新的CustomArrayResolver(container.Kernel,typeof(IIface));
请发布一个完整的测试用例。我刚刚在Mono下尝试了我的示例(我家没有windows)Windsor 2.1,它没有解析任何类。正确的粘贴在这里,我从中运行.net 4.0 Windsor,所以你是说mono下的Windsor 2.1按预期工作,而head版本抛出?否:)技巧是mono在第二种情况下创建实例,忽略约束!但在编译时它显示了一个错误,请参见:var qwe=new handlerimp();是的,在此期间,在我们修复错误之前,这是一个很好的解决方法:)感谢您的解决方案!顺便说一句,你能在像我这样的完整测试用例中演示如何“正常地”注入吗?@xumix:所谓“正常地”,我的意思是不直接调用ResolveAll()。在执行正常注入时,不直接调用Resolve()或ResolveAll(),而是让容器解析它必须解析的内容。否则,您将执行服务定位器,而不是依赖项注入。请参阅中的ResolveAll\u CustomResolver()
,我已经研究了您的示例,但我看到了相同的Resolve/All调用。@xumix:您需要区分应用程序代码和基础结构代码。ISubDependencyResolver是基础架构,非常特定于Windsor,您可以在那里使用Resolve。对测试本身的Resolve()调用就在这里,因为我们在这里测试容器本身。这不是常规的应用程序代码。关键是,服务
(即应用程序代码)通常会被注入IIface
数组,它不会直接调用容器。谢谢!顺便说一句,主干版本似乎没有使用IHandlerSelector。我试过这个,但我的选择器从未被调用。或者仅在正常注入中调用IHandlerSelector/ISubDependencyResolver?它们用于解析单个组件<代码>全部解析。。。好吧-解决所有问题,所以这里没有什么真正需要决定的。
public class CustomArrayResolver : ISubDependencyResolver {
private readonly IKernel kernel;
private readonly Type serviceTypeDefinition;
public CustomArrayResolver(IKernel kernel, Type serviceTypeDefinition) {
this.kernel = kernel;
this.serviceTypeDefinition = serviceTypeDefinition;
}
private bool MatchesConstraints(Type service, Type impl) {
try {
impl.MakeGenericType(service.GetGenericArguments());
return true;
} catch (ArgumentException) {
return false;
}
}
public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency) {
var service = dependency.TargetType.GetElementType();
var handlers = kernel.GetAssignableHandlers(service);
var components = handlers
.Where(h => h.CurrentState == HandlerState.Valid)
.Where(h => MatchesConstraints(service, h.ComponentModel.Implementation))
.Select(h => h.Resolve(context, contextHandlerResolver, model, dependency))
.ToArray();
var r = Array.CreateInstance(service, components.Length);
components.CopyTo(r, 0);
return r;
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency) {
return dependency.TargetType != null &&
dependency.TargetType.IsArray &&
kernel.HasComponent(dependency.TargetType.GetElementType()) &&
dependency.TargetType.GetElementType().IsGenericType &&
dependency.TargetType.GetElementType().GetGenericTypeDefinition() == serviceTypeDefinition;
}
}
container.Kernel.Resolver.AddSubResolver(new CustomArrayResolver(container.Kernel, typeof(IIface<,>)));