如何使Castle windsor解决具有约束的泛型?

时间:2010-06-18 15:33:41

标签: 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 (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<IIface<Impl2, Stub>> (); // this works ok
var ex = container.ResolveAll<IIface<Impl1, Stub>> (); // this throws exception abou not fullfilled constraints
// instead i want it just show no resolved implementations

有没有办法按照我的意愿来完成这项工作?

2 个答案:

答案 0 :(得分:3)

实际上这似乎是温莎代码中的一个错误。

更新

现在已修复

答案 1 :(得分:1)

如果您正常注入事物(即使用ArrayResolver而不是直接调用ResolveAll()),您可以使用仅适用于此类型的自定义数组解析器(或针对具有此问题的类型)解决此问题:< / p>

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;
    }       
}

在标准ArrayResolver之前注册:

container.Kernel.Resolver.AddSubResolver(new CustomArrayResolver(container.Kernel, typeof(IIface<,>)));