c# - SimpleInjector HowTo Register multiple Open Generic Interfaces for a Single Generic Implementation -
i'm trying started simpleinjector ioc container , i'm pretty happy it. right i'm stuck on problem can't solve. searched on , in documentation, seems not answered yet. i've seen the howto doc simpleinjector doesn't cover open generic interfaces.
i have 2 generic interfaces these:
public interface ieventpublisher<tevent> { void publish(tevent event); } public interface ieventsubscriber<tevent> { void subscribe(action<tevent> callback); }
and 1 open generic implementation two:
class eventmediator<t> : ieventpublisher<t>, ieventsubscriber<t> { list<action<t>> subscriptions = new list<action<t>>(); public void publish(t event) { foreach (var subscription in this.subscriptions) subscription.invoke(event); } public void subscribe(action<t> callback) { this.subscriptions.add(callback); } }
in application i'm setting simpleinjector this:
this.container = new simpleinjector.container(); this.container.registeropengeneric(typeof(ieventpublisher<>), typeof(eventmediator<>), lifestyle.singleton); this.container.registeropengeneric(typeof(ieventsubscriber<>), typeof(eventmediator<>), lifestyle.singleton); this.container.verify();
what i'm trying archive is: i'd same instance when asking ieventpublisher or ieventsubscriber. , furthermore instance shall singleton t.
i've tested these lines:
class dummyevent {} var p = this.container.getinstance<ieventpublisher<dummyevent>>(); var s = this.container.getinstance<ieventsubscriber<dummyevent>>(); var aresame = (object.referenceequals(p,s));
unfortunatly p , s don't refer same instance. happens know solution problem?
there solutions this, here's one: create separate implementations ieventpublisher<t>
, ieventsubscriber<t>
, let them delegate eventmediator<t>
. instance these implementations:
public class eventpublisher<tevent> : ieventpublisher<tevent> { private readonly eventmediator<tevent> mediator; public eventpublisher(eventmediator<tevent> mediator) { this.mediator = mediator; } public void publish(tevent event) { this.mediator.publish(event); } } public class eventsubscriber<tevent> : ieventsubscriber<tevent> { private readonly eventmediator<tevent> mediator; public eventsubscriber(eventmediator<tevent> mediator) { this.mediator = mediator; } public void subscribe(action<tevent> callback) { this.mediator.subscribe(callback); } }
now make registrations follows:
container.registersingleopengeneric(typeof(eventmediator<>), typeof(eventmediator<>)); container.registersingleopengeneric(typeof(ieventpublisher<>), typeof(eventpublisher<>)); container.registersingleopengeneric(typeof(ieventsubscriber<>), typeof(eventsubscriber<>));
now both eventpublisher<dummyevent>
, eventsubscriber<dummyevent>
point @ same eventmediator<dummyevent>
instance.
another way achieve without type make use of resolveunregisteredtype
event (which registeropengeneric
extension method uses under covers). configuration this:
container.registersingleopengeneric(typeof(eventmediator<>), typeof(eventmediator<>)); container.resolveunregisteredtype += (s, e) => { if (e.unregisteredservicetype.isgenerictype) { var def = e.unregisteredservicetype.getgenerictypedefinition(); if (def == typeof(ieventpublisher<>) || def == typeof(ieventsubscriber<>)) { var mediatortype = typeof(eventmediator<>) .makegenerictype(e.unregisteredservicetype.getgenericarguments()[0]); var producer = container.getregistration(mediatortype, true); e.register(producer.registration); } } };
you extract code more general extension method. way registration this:
container.registersingleopengeneric(typeof(eventmediator<>), typeof(eventmediator<>)); container.forwardopengenericto(typeof(ieventpublisher<>), typeof(eventmediator<>)); container.forwardopengenericto(typeof(ieventsubscriber<>), typeof(eventmediator<>));
the extension method this:
public static void forwardopengenericto(this container container, type opengenericservicetype, type opengenericservicetypetoforwardto) { container.resolveunregisteredtype += (s, e) => { var type = e.unregisteredservicetype; if (type.isgenerictype) { if (type.getgenerictypedefinition() == opengenericservicetype) { var forwardtotype = opengenericservicetypetoforwardto.makegenerictype( type.getgenericarguments()); var producer = container.getregistration(forwardtotype, true); e.register(producer.registration); } } }; }
Comments
Post a Comment