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<,>)));