Как заставить Виндзор Касла разрешать дженерики с ограничениями? - PullRequest
3 голосов
/ 18 июня 2010
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 ]

3 голосов
/ 19 июня 2010

На самом деле это похоже на ошибку в коде Виндзора.

Обновление:

И теперь это исправлено

1 голос
/ 19 июня 2010

Если вы вводите что-то обычным образом (т. Е. Используя ArrayResolver и не вызываете ResolveAll() напрямую), вы можете обойти его с помощью специального распознавателя массива только для этого типа (или для типов, имеющих эту проблему):

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<,>)));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...