dependency injection - Castle Windsor Typed Factory Facility with generics -
i'm trying register factory resolve array of event handlers defined follow:
public interface ievent { } public class eventa : ievent { } public class eventb : ievent { } public class eventc : ievent { } public interface ihandler<tevent> 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); }
basically each event can have more handlers , each handler can handle multiple events. want factory return object[] because @ runtime don't know closed generic types returned.
i tried approach descirbed krzysztof koźmic http://kozmic.pl/2010/03/11/advanced-castle-windsor-ndash-generic-typed-factories-auto-release-and-more/ still have problems. question boils down types return custom type deriving defaulttypedfactorycomponentselector.
i tried many variations of following:
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; }*/ }
with windsor installer defined as:
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>())); } }
when calling factory.gethandlersforevent(ev); exception complaining array type mismatch: "attempted access element type incompatible array."
stack trace:
at system.collections.generic.dictionary2.valuecollection.copyto(tvalue[] array, int32 index)
2.valuecollection.system.collections.icollection.copyto(array array, int32 index)
@ system.collections.generic.dictionary
@ castle.microkernel.defaultkernel.resolveall(type service, idictionary arguments) in e:\oss.code\castle.windsor\src\castle.windsor\microkernel\defaultkernel_resolve.cs:line 285
@ castle.facilities.typedfactory.typedfactorycomponentcollection.resolve(ikernel kernel) in e:\oss.code\castle.windsor\src\castle.windsor\facilities\typedfactory\typedfactorycomponentcollection.cs:line 39
@ castle.facilities.typedfactory.internal.typedfactoryinterceptor.resolve(iinvocation invocation) in e:\oss.code\castle.windsor\src\castle.windsor\facilities\typedfactory\internal\typedfactoryinterceptor.cs:line 173
@ castle.facilities.typedfactory.internal.typedfactoryinterceptor.intercept(iinvocation invocation) in e:\oss.code\castle.windsor\src\castle.windsor\facilities\typedfactory\internal\typedfactoryinterceptor.cs:line 83
@ castle.dynamicproxy.abstractinvocation.proceed()
@ castle.proxies.handlerfactoryproxy.gethandlersforevent(ievent ev)
@ castlewindsortests.program.tryit(handlerfactory factory) in c:\users\user\documents\visual studio 2010\projects
how implement handlerselector works factory defined returning object[] whereas real objects @ runtime closed generic types? i'll happy pointed existing documentation guidelines implementors of itypedfactorycomponentselector / defaulttypedfactorycomponentselector. yes, tried http://docs.castleproject.org/(s(kwaa14uzdj55gv55dzgf0vui))/windsor.typed-factory-facility-interface-based-factories.ashx here's not above types.
i don't want introduce service locator (instead of factory) ;).
to answer own question:
i must've been blind. after reading more closely xmldoc of methods override, changing handlerselector following solved problem:
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; } }
Comments
Post a Comment