How to get Castle Windsor to allow generics with restrictions?

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

So now, if I do smth. like:

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

Is there any way to make this work the way I want it?

+3
source share
2 answers

Actually this seems to be a bug in Windsor code.

Update:

And now it is fixed

+3
source

If you usually do injections (i.e. use ArrayResolver and do not call ResolveAll()), you can bypass it using a special array recognizer only for this type (or for types that have this problem):

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

Register it right before the standard ArrayResolver:

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

Source: https://habr.com/ru/post/1750703/


All Articles