c# - How to inject dependencies via a construction delegate -


i'm using third-party library has setup structure this:

iengine engine = /* singleton provided elsewhere */  var server = new fooserver(); server.addservice("data1", () => new data1(engine)); server.addservice("data2", () => new data2(engine)); server.start(); ... server.dispose(); 

(the lambda factory method; internally invoke whenever wants new instance own purposes.)

except further complication instead of adding services directly, i'm using reflection find , register them, need defined work instead of needing explicitly listed out. wanted self-contained, constructing generic lambda methods based on reflected types seemed complicated, moment i've settled register method provided each type:

class data1 : dataprovider {     public static void register(fooserver server, iengine engine)     {         server.addservice("data1", () => new data1(engine));     }     ... (constructor, dispose, other stuff) }  var server = new fooserver(); foreach (var type in utils.getconcretetypeswithbase<dataprovider>()) {     var method = type.getmethod("register", new[] { typeof(fooserver), typeof(iengine) });     if (method != null)     {         method.invoke(null, new object[] { server, engine });     }     // more ideal approach construct needed lambda , call     // addservice directly instead of using register, brain fails me. } server.start(); ... server.dispose(); 

needless say, bit ugly , i'm sure there's better way it. 1 other thing i'm using castle windsor create iengine , few other things use it, , wondering how better integrate that. (currently i'm resolveing engine @ point code needs -- it's singleton lifetimes aren't thorny.)

what i'd love way use method parameter or constructor injection each dataprovider have different set of parameters based on actual dependencies (instead of union of dependencies), you'd when under windsor's control. again, i'm not sure start. haven't used windsor beyond basics.

note fooserver, dataprovider , addservice<t>(string name, func<t> factory) t: dataprovider method in external code , can't change them. rest (including engine) code. , again note not create data1 instances in code @ all, factory lambda tells external server how create them when wants one.


following qujck's answer few necessary edits resulted in following code, posterity:

var container = ...; var server = new fooserver(); foreach (var type in utils.getconcretetypeswithbase<dataprovider>()) {     var t = type;  // necessary due lambda capturing     container.register(component.for(t).lifestyletransient());     server.addservice(t.name, () => {         var service = (dataprovider) container.resolve(t);         service.closed += (s, e) => container.release(service);         return service;     }); } server.start(); ... server.dispose(); 

this behaves desired, though i'm still interested in methods improve further. (i curious if there way use castle's own classes.fromassembly... etc syntax tidy discovery , registration of services, haven't had luck working out.)

you define lambda's resolve container. offers benefits of managing of services , related lifetimes in 1 place (the container).

you need way of establishing name of each registration - in example have registered each service name of type:

[fact] public void configure1() {     iwindsorcontainer container = new windsorcontainer();     var server = new mockfooserver();      container.register(component.for<iengine>().implementedby<engine>());     foreach (type type in utils.getconcretetypeswithbase<dataprovider>())     {         container.register(component.for(type));         server.addservice(type.name, () => container.resolve(type) dataprovider);     }      var service1 = server.services[typeof(service1).name]();      assert.istype<service1>(service1); } 

with mock fooserver test:

public class mockfooserver {     public dictionary<string, func<dataprovider>> services =          new dictionary<string, func<dataprovider>>();      public void addservice<t>(string key, func<t> factory) t : dataprovider     {         this.services.add(key, factory func<dataprovider>);     } } 

Comments

Popular posts from this blog

c++ - OpenMP unpredictable overhead -

ruby on rails - RuntimeError: Circular dependency detected while autoloading constant - ActiveAdmin.register Role -

javascript - Wordpress slider, not displayed 100% width -