Замок Виндзорский завод типовых заводов с дженериками - PullRequest
3 голосов
/ 11 мая 2011

Я пытаюсь зарегистрировать фабрику, которая могла бы разрешить массив обработчиков событий, определенных следующим образом:

    public interface IEvent { }

    public class EventA : IEvent { }
    public class EventB : IEvent { }
    public class EventC : IEvent { }


    public interface IHandler<TEvent> where TEvent : IEvent
    {
        void Handle(TEvent ev);
    }


    public class HandlerX : IHandler<EventA>, IHandler<EventB>
    {
        public void Handle(EventA ev)
        {
            throw new NotImplementedException("handle EventA");
        }

        public void Handle(EventB ev)
        {
            throw new NotImplementedException("handle EventB");
        }
    }

    public class HandlerY : IHandler<EventB>, IHandler<EventC>
    {
        public void Handle(EventB ev)
        {
            throw new NotImplementedException("handle EventB");
        }

        public void Handle(EventC ev)
        {
            throw new NotImplementedException("handle EventC");
        }
    }

    public interface HandlerFactory
    {
        object[] GetHandlersForEvent(IEvent ev);
    }

В принципе, для каждого события у меня может быть больше обработчиков, и каждый обработчик может обрабатывать несколько событий. Я также хочу, чтобы фабрика возвращала объект [], потому что во время выполнения я не знаю, какие закрытые универсальные типы будут возвращены.

Я попробовал подход, описанный Кшиштофом Козьмичем http://kozmic.pl/2010/03/11/advanced-castle-windsor-ndash-generic-typed-factories-auto-release-and-more/ но все еще есть проблемы. По сути, мой вопрос сводится к тому, какие типы возвращать из моего пользовательского типа, полученного из DefaultTypedFactoryComponentSelector.

Я пробовал много вариантов следующего:

public class HandlerSelector : DefaultTypedFactoryComponentSelector
    {
        protected override TypedFactoryComponent BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, System.Collections.IDictionary additionalArguments)
        {
            Type eventType = null;
            foreach (var k in additionalArguments.Values)
            {
                eventType = k.GetType();
            }

            var handlerType = typeof(IHandler<>).MakeGenericType(eventType);
            var handlerArrayType = handlerType.MakeArrayType();
            //return handlerArrayType;
            return new TypedFactoryComponentCollection(handlerType, additionalArguments);
        }

        protected override Type GetComponentType(MethodInfo method, object[] arguments)
        {
            return typeof (object);
            /*
            var message = arguments[0];
            var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
            var handlerArrayType = handlerType.MakeArrayType();
            return handlerArrayType;
             */
        }

        /*
        public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments)
        {
            var message = arguments[0];
            var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
            var result = new TypedFactoryComponentCollection(handlerType.MakeArrayType(), new Arguments(arguments));
            return result;
        }*/
    }

с установщиком Windsor, определенным как:

public class Installer : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.AddFacility<TypedFactoryFacility>()
                .Register(
                    Component.For<HandlerSelector>().ImplementedBy<HandlerSelector>(),
                    Component.For<AutoReleaseHandlerInterceptor>(),
                    AllTypes.FromAssemblyContaining<Program>()
                        .BasedOn(typeof(IHandler<>))
                        .WithService.Base()
                        .Configure(c => c.LifeStyle.Is(LifestyleType.Transient)
                                            .Interceptors<AutoReleaseHandlerInterceptor>()),
                    Component.For<HandlerFactory>().AsFactory(c => c.SelectedWith<HandlerSelector>()));
        }
    }

При вызове factory.GetHandlersForEvent (ev); Я получаю исключение, сообщающее о несоответствии типов массивов: "Попытка доступа к элементу как к типу, несовместимому с массивом."

Трассировка стека:

в System.Collections.Generic.Dictionary 2.ValueCollection.CopyTo(TValue[] array, Int32 index)<br> at System.Collections.Generic.Dictionary 2.ValueCollection.System.Collections.ICollection.CopyTo (массив массивов, индекс Int32)
в Castle.MicroKernel.DefaultKernel.ResolveAll (Служба типа, аргументы IDictionary) в e: \ OSS.Code \ Castle.Windsor \ src \ Castle.Windsor \ MicroKernel \ DefaultKernel_Resolve.cs: строка 285
в Castle.Facilities.TypedFactory.TypedFactoryComponentCollection.Resolve (ядро IKernel) в e: \ OSS.Code \ Castle.Windsor \ src \ Castle.Windsor \ Facilities \ TypedFactory \ TypedFactoryComponentCollection.cs: строка 39
в Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Resolve (вызов IInvocation) в e: \ OSS.Code \ Castle.Windsor \ src \ Castle.Windsor \ Facilities \ TypedFactory \ Internal \ TypedFactoryInterceptor.cs: строка 173 * 10 * в Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Intercept (вызов IInvocation) в e: \ OSS.Code \ Castle.Windsor \ src \ Castle.Windsor \ Facilities \ TypedFactory \ Internal \ TypedFactoryInterceptor.cs: строка 83
at Castle.DynamicProxy.AbstractInvocation.Proceed ()
at Castle.Proxies.HandlerFactoryProxy.GetHandlersForEvent (IEvent ev)
в CastleWindsorTests.Program.TryIt (фабрика HandlerFactory) в каталоге c: \ users \ user \ documents \ visual studio 2010 \ Projects

Как реализовать HandlerSelector, чтобы он хорошо работал с фабрикой, определенной как возвращающий объект [], тогда как реальные объекты во время выполнения являются закрытыми универсальными типами? Я буду рад указать на существующую документацию с рекомендациями для разработчиков ITypedFactoryComponentSelector / DefaultTypedFactoryComponentSelector. Да, я попробовал http://docs.castleproject.org/(S(kwaa14uzdj55gv55dzgf0vui))/Windsor.Typed-Factory-Facility-interface-based-factories.ashx, но здесь не так много о вышеупомянутых типах.

Я действительно не хочу вводить сервисный локатор (вместо фабричного);).

Ответы [ 2 ]

3 голосов
/ 13 мая 2011

Чтобы ответить на мой собственный вопрос:

Я, должно быть, был слепым.После более детального изучения xmldoc методов, которые я переопределяю, изменение HandlerSelector на следующее решило проблему:

public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
    protected override TypedFactoryComponent BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, System.Collections.IDictionary additionalArguments)
    {                
        return new TypedFactoryComponentCollection(componentType, additionalArguments);
    }

    protected override Type GetComponentType(MethodInfo method, object[] arguments)
    {
        var message = arguments[0];
        var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
        return handlerType;
    }
}
1 голос
/ 05 апреля 2015

@ workabyte

Для Castle v3 метод GetComponentType остается прежним, но метод BuildFactoryComponent выглядит для меня так:

protected override Func<IKernelInternal, IReleasePolicy, object> BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, IDictionary additionalArguments)
{
    return (kernel, rp) => kernel.ResolveAll(componentType);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...