Using default constructor and parameterised constructor in unity c# -
i have application uses unity fw resolve objects throughout. have done change framework , classes can seen in code comment "new change"
the wrapper class looks like
public static class contractresolver { public static t resolve<t>() //this been used in many places in application { iunitycontainer container = new unitycontainer(); var section = (unityconfigurationsection)configurationmanager.getsection("unity"); section.containers.default.configure(container); return container.resolve<t>(); } //new change: new function suppose return instance of parameterised constructor public static t resolve<t>(parameteroverride[] parameteroverrides) { iunitycontainer container = new unitycontainer(); var section = (unityconfigurationsection)configurationmanager.getsection("unity"); section.containers.default.configure(container); return container.resolve<t>(parameteroverrides); } }
the configuration looks like
<unity> <containers> <container> <types> <type type ="unitytest.iimagerepositoryservice, unitytest" mapto="unitytest.imagerepositoryservice, unitytest"/> </types> </container> </containers> </unity>
the classes , interface looks like
public interface iimagerepositoryservice { bool exists(string imagename); } public class imagerepositoryservice : iimagerepositoryservice { private readonly string mfiltername = "standardimagefilter"; //[injectionconstructor] public imagerepositoryservice() { databasequeryprovider.query("image", mfiltername); } //new change. constructor accepts parameter //[injectionconstructor] public imagerepositoryservice(string filtername) { mfiltername = filtername; databasequeryprovider.query("image", filtername); } public bool exists(string imagename) { console.writeline("the image " + imagename + " found in filter " + mfiltername); return true; } }
the usage looks like
var servicedefault = contractresolver.resolve<iimagerepositoryservice>(); servicedefault.exists("myimage.bmp");
the new changes breaks old usage. i.e.
var servicedefault = contractresolver.resolve<iimagerepositoryservice>();
throws exception resolution of dependency failed, type = "unitytest.iimagerepositoryservice", name = "(none)". exception occurred while: while resolving. exception is: invalidoperationexception - type string cannot constructed. must configure container supply value.
i have new functionality @ same time not want break old functionality.
var servicedefault = contractresolver.resolve<iimagerepositoryservice>(); servicedefault.exists("myimage.bmp");
should display message in console "the image myimage.bmp found in filter standardimagefilter"
var parameteroverride1 = new parameteroverride("filtername", "filter1"); var servicefilter1 = contractresolver.resolve<iimagerepositoryservice>(new[] { parameteroverride1 }); servicefilter1.exists("myimage.bmp");
should display message in console "the image myimage.bmp found in filter filter1"
var parameteroverride2 = new parameteroverride("filtername", "filter2"); var servicefilter2 = contractresolver.resolve<iimagerepositoryservice>(new[] { parameteroverride2 }); servicefilter2.exists("myimage.bmp");
should display message in console "the image myimage.bmp found in filter filter2"
how solve problem?
if want resolve same type (in case iimagerepositoryservice
) have different calls resolve invoke different constructors need use named registrations.
in case can in xml configuration:
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <container> <register type ="unitytest.iimagerepositoryservice, unitytest" mapto="unitytest.imagerepositoryservice, unitytest"> <constructor /> </register> <register name="parameterizedrepository" type="unitytest.iimagerepositoryservice, unitytest" mapto="unitytest.imagerepositoryservice, unitytest"> <constructor> <param name="filtername" value="dummyvalue" /> </constructor> </register> </container> </unity>
note, i've used unity 2 (and 3) configuration style.
so tells unity when resolving using name "parameterizedrepository" invoke constructor parameter named "filtername". i've used dummy value here because going override value @ runtime anyway:
var imagerepositoryservice = container.resolve<iimagerepositoryservice>( "parameterizedrepository", new parameteroverride("filtername", "filter2"));
so that's how want using unity in terms of wrapper class should add name parameter:
public static class contractresolver { //new change: new function suppose return instance of parameterised constructor public static t resolve<t>(string name, params parameteroverride[] parameteroverrides) { iunitycontainer container = new unitycontainer(); var section = (unityconfigurationsection)configurationmanager.getsection("unity"); section.containers.default.configure(container); return container.resolve<t>(name, parameteroverrides); } }
a few unsolicited comments (in spirit of trying helpful):
it looks using unity version 1. if so, might want consider upgrading (version 3 released recently) , if not using unity version 1, might want consider changing xml configuration syntax use newer approach using
loadconfiguration()
extension method.i'm not sure why every call
contractresolver.resolve()
creates new unity container , loads configuration. bit of performance hit. usually, create container , load configuration once , use instance lifetime of application.i can understand how tempted hide container implementation behind
contractresolver
addition ofparameteroverride
(which unity specific) abstraction becoming bit leaky.
Comments
Post a Comment