您的位置:首页 > 移动开发

SCSF - Part 5 Dependency Injection and the Composite Application Block

2013-10-18 14:56 330 查看
IntroductionInpart1ofthisseriesofarticlesIdescribedasimpleCABapplication.ThishadthreeWindowsApplicationC#projectswithnoreferencestoeachother.Inspiteofthis,withsomeverysimplecodewecouldgetallthreetolaunchtheirindividualscreens.Thatverysimpleapplicationdidn’thavetheprojectsinteractinginanyotherway,however.part1描述了最简单的cab应用程序,它拥有三个彼此没有相互引用的windows应用程序,尽管如此,用一些很简单的代码我们也可以让这仨调用他们自己的form,但是他们直接并不能相互通信。Part2oftheseriesdescribedWorkItems,whichcanbethoughtofascontainersforcode,andhowwecouldaddaWorkItemtoeachofourprojectsinahierarchy.part2描述了workitems,我们可以把他看做是一个code的容器,并且我们是如何将workitem加到我们的projects里的Part3introduceddependencyinjectionasawayofstructuringourcodesothatourclassstructurewaslooselycoupledandbehaviourcouldbeeasilychangedbychangingwhichclasswas‘injected’intoanother.part3介绍了依赖注入是一种结构化我们代码的方法我们的代码结构可以变得很松散,并且可以轻易地通过更改注入类来更改功能。InthisarticleIwillbringalloftheseideastogetherandexplainhowdependencyinjectionworksintheCAB.这篇文章我将把这些内容串在一起,并且解释依赖注入是怎么在cab里运作的。TheProblemWewanttogetourthreeprojectsfrompart1(Red,BlueandShell)tointeractwitheachotherwithouthavingthemreferenceeachother.Asdiscussedinpart2,WorkItemsaredesignedtoallowustodothis:wecanputaWorkItemineachproject,putcodeintotheirvariouscollections,sharetheWorkItemsandthussharethecode.ButhowdoesoneprojectknowabouttheWorkItemfromanotherproject?Bearinmindthattherearenodirectreferencesbetweentheprojects.Thiscouldbedonemanuallyincodeusingreflection,ofcourse.ButtheCABframeworkgivesusamuchcleanerwaytodothis.我们想让我们的三个项目可以相互通信却不相互引用,正如part2里提到的,workitems就是为了这个目的而被设计出来的,我们可以让每个project里都放置一个workitem,把代码房子他们的collections里面,共享workitem从而共享了code。DependencyInjectionandtheCABTheansweriswecanusedependencyinjectiontoinjectaWorkItemfromoneprojector‘module’intoanother.Thisisclearlyanappropriatethingtodohere:wewantloosecouplingbetweenourmodulesandflexibilitytochangehowtheyinteract.AsI’vediscussedinanotherarticle,inextremecaseswemighthavedifferentdevelopmentteamsresponsiblefordifferentmodules,withdifferentreleasecycles.Usingdependencyinjectiononeteamcouldchangeaclassthat’sinjectedandthuschangethebehaviourofanothermodulewithoutthatmoduleneedingtobere-released.However,unlikeinmyexampleinpart3,dependencyinjectionintheCABdoesn’tuseconfigurationfilestospecifywhichclassshouldbeused.Insteadattributesareusedtotellthecodethatadependencyneedstobeinjected.答案是我们可以使用依赖注入去注入一个workitem从一个project或者module到另一个。这是我们可以做的非常合适的事让我使得模块之间更松耦合,更具伸展性。就像我以前讨论过的,有个case,我们也许有连个不同的开发小组负责不同的有着不一样发布周期的模块,使用依赖注入一个小组可以通过改变注入的class使得另一个模块的表现发生变化并且不需要另外一个模块重新发布。然而,不像我在part3里解释的,cab里的依赖注入并不适用配置文件去具体化哪个class需要被使用,我们在这里使用attributeExampleThisismosteasilyseenwithanexample.WehavealreadyseenthatarootWorkItemiscreatedinourCABapplicationatstartup.WehavealsoseenthatallmoduleslistedintheProfileCatalog.xmlfilewillgetloadedatthestartupofaCABapplication,andthataLoad()methodinaModuleInitclassgetscalledineachmodule.WewantareferencetotherootWorkIteminamodulethatisnottheshell.WecanachievethisbyputtingasetterforaWorkIteminourModuleInitclassforthemodule,alongwithanattribute:这是一个最简单的例子,我们已经看到这个rootworkitem在cab程序启动的时候被创建了,我们还看到其他所有在profilecatalog.xml文件里的模块会在cab应用程序开始的时候被加载,而且,在moduleinit类的load()方法会被调用。我们想在不是shell的module里有对workitem的引用,我们可以通过为workitem设置一个有属性的setter来达到这点。
privateWorkItemparentWorkItem;
[ServiceDependency]
publicWorkItemParentWorkItem
{
set
{
parentWorkItem=value;
}
}
Asyoucanseewedecoratethesetterwiththeattribute‘ServiceDependency’.ThistellstheCABframeworkthatwhenitisloadingthismoduleitshouldlookforanappropriateWorkItemto‘inject’intothissetter.IfweputthiscodeintotheRedModuleInitclassinourexample,andputabreakpointinthesetterwecanseethattherootWorkItemisbeingpassedintohereatstartupandstoredintheparentWorkItemvariable.像你所看到的,我们给set装饰上了attribute“ServiceDependency',这告诉了cab的framework当它在装载模块的时候,它需要寻找一个合适的workitem去注入。如果我们把这代码放到这个例子中的redimoduleinit这个class里,并且设置一个断点在setter上,我们可以发现在启动的时候rootworkitem被pass到这里,并且被存在parentworkitem这个变量里。HowisthisWorking(1)?YoumaywonderhowtheCABknowswhattoinjectandwheretoinjectithere.AfteralltheremaybemultipleWorkItemsinourproject:whichoneshoulditchoose?Furthermorewecaninjectdifferenttypes(i.e.notWorkItems)inasimilarway.Ifwehaveseveralinstantiatedclassesofthesametypehowdoweinjectaspecificone?AndhowdoestheCABfindtheServiceDependencyattribute?Doesitscanallclassesinallmodules?I’mgoingtoleavetheseissuesfornow:justacceptthattherootWorkItemgetsinjectedinthiscase.I’llreturntothislaterinthisarticle.你也许会感到疑惑cab是怎么知道inject什么,inject到哪里,毕竟有也许在我们的project里有许多workitem,哪一个会被选中,此外我们可以通过类似的办法注入其他不同的类型(不仅是workitems),如果我们有许多实例化同一个类的对象,我们如何去注入一个指定的?而且cab又是如何找到servicedependency这个属性的呢?它扫面了所有的module了吗?我将先搁置这些问题,只是接受rootworkitem被注入了。我会在文章的后面再次提及。RedandBlueFormsApplicationSowecangetareferencetotherootWorkItemasabove.Inourna?veCABapplicationfrompart1we’dquiteliketotelltheredandblueformsinthemodulestoloadasMDIchildrenintotheshellform.WecandothisbyfirstlyaddingtheshellformtotheItemscollectionoftherootWorkItem.TheniftherootWorkItemisavailableinourRedandBlueprojectswecanaccesstheshellformthroughtheItemscollection.There’sanAfterShellCreatedeventoftheFormShellApplicationclassthatwecanoverrideinourprogramclasstoaddtheshellformtotheItemscollection:我们得到了rootworkitem的引用,在part1,在我们的cab应用程序里,我们十分想让红与蓝项目能够成为shellform的子项目,我们可以首先可以把shellform加到rootworkitem里,然后如果rootworkitem在红蓝项目里能够被用到,那我们就可以通过itemcollection访问到shellform了
publicclassProgram:FormShellApplication<WorkItem,Form1>
{
[STAThread]
staticvoidMain()
{
newProgram().Run();
}
protectedoverridevoidAfterShellCreated()
{
base.AfterShellCreated();
this.Shell.IsMdiContainer=true;
RootWorkItem.Items.Add(this.Shell,"Shell");
}
}


NotethattheshellgetsanameintheItemscollection(“Shell”).Notealsothatwe’remakingtheshellformintoanMDIContainerhere,accessingitviatheShellpropertyoftheFormShellApplicationclass.IntheLoadmethodofourmoduleswecannowretrievetheshellformandsetittobetheMDIParentofourredandblueforms.SoourModuleInitclasslooksasbelow:注意到这个item有个名字"shell“,注意到我们也将这个shellform放到mdicontainer里,可以通过这个formshellapplication类里的shell属性访问到。在我们的load方法里,我们现在可以得到shellform并将它设置成红和蓝forms的midiparent。publicclassRedModuleInit:ModuleInit { privateWorkItemparentWorkItem; [ServiceDependency] publicWorkItemParentWorkItem { set { parentWorkItem=value; } } publicoverridevoidLoad() { base.Load(); Formshell=(Form)parentWorkItem.Items["Shell"]; Form1form=newForm1(); form.MdiParent=shell; form.Show(); } }
IfwenowruntheapplicationourredandblueformswillappearasMDIchildrenofthemainshell.Thecodeforthisisavailable.BythewayyoushouldknowthattherearebetterwaysofsettingupanMDIapplicationintheCAB:thisexampleisintendedtojustshowthebasicconceptsofdependencyinjection.如果我们现在在跑这个应用程序我们的红蓝form将会作为子出现在mainshell里,顺便说一句,你应该知道有许多更好的方法来实现这个,这个例子主要是告诉你一些基本的依赖注入的概念。HowisthisWorking(2)?EarlierinthisarticleIposedseveralquestionsabouthowallthiscouldbeworking.I’llattempttoanswerthosequestionsnow.Asdiscussedearlier,WorkItemsaregenericcontainersforcodetobepassedbetweenmodules,andarecapableofbeingarrangedinahierarchy.Butinadditiontheyareactually‘InversionofControlcontainers’or‘DependencyInjectioncontainers’.Imentionedtheseinpart4ofthisseriesofarticles.However,I’veratherglossedoverthemupuntilnow.NotethatbothSpringandPicoContainerusecontainerstocontroltheirdependencyinjection.在这篇文章的前面,我提了一些问题,关于这个是如何实现的,现在我将试着去回答这些问题。正如我们之前讨论过的,workitems是一个泛型的containers,可以让代码传入到workitem里,并且能够被安排成树状结构,并且他们是反转控制containers和依赖注入containers,然而,知道现在我一直都在粉饰,spring和picocontainer使用containers来控制依赖注入。WorkItemsasDependencyInjectionContainersThesecontainersworkintheCABasfollows.SupposewewanttoinjectobjectAintoobjectB.ThedependencyinjectiononlyhappenswhenobjectBisaddedintoanappropriatecollectiononaWorkItem.ThiscanbeoncreationoftheobjectifwecreateobjectBwiththeAddNewmethod,oritcanhappenwithanexistingobjectifweusetheAddmethodtoaddittoaWorkItemcollection.FurthermorenormallytheinjectioncanonlyworkifobjectAisalreadyinanappropriatecollectionofthesameWorkItem.Theexceptionisifweareusingthe‘CreateNew’attribute(seebelow).InthiscaseobjectAwillbecreatedandaddedtotheItemscollectionoftheWorkItembeforebeinginjected.Asyoucansee,inawaydependencyinjectionintheCABis‘scoped’toaWorkItem.这些containers在cab里是这样工作的,假设我们想将objectA注入到objectB,这个依赖注入只有在当我们将objectB作为一个workitem加入到一个合适的collection里的时候才会发生。我们可以通过addnew方法来实现这一点,或者我们可以先new然后再通过add方法加入。此外,通常情况下这个注入只有在objectA本来就在同一个workitem的一个合适的collection里,除非我们用createnew属性标记了objectA,在这种情况下objectA在被注入之前会被创建并且加入到这个itemcollection里TypesofDependencyInjectionintheCABTherearethreeattributesthatcanbeattachedtosettersandusedfordependencyinjectionintheCAB:有三种attribute可以加在setters之上用于依赖注入。ComponentDependency(stringId)
ThisattributecanbeusedtoinjectanyobjectthatalreadyexistsinaWorkItem’sItemscollection.However,becausewecanhavemultipleobjectsofthesametypeinthiscollectionwehavetoknowtheIDoftheitemwewanttoinject(whichisastring).WecanspecifyanIDwhenweaddourobjectintothecollection.Ifwedon’tspecifyanIDtheCABassignsarandomGUIDtotheitemasanID.NotethatiftheobjectdoesnotexistintheappropriateItemscollectionwhenwetrytoinjectitthentheCABwillthrowaDependencyMissingException.
ServiceDependency
We’veseenthisattributealready.AnobjectmustbeintheWorkItem’sServicescollectiontobeinjectedusingthisattribute.TheServicescollectioncanonlycontainoneobjectofanygiventype,whichmeansthatthetypeofthesetterspecifiestheobjectuniquelywithouttheneedforanID.IwilldiscussServicesfurtherinpart6ofthisseriesofarticles.
CreateNew
Anewobjectoftheappropriatetypewillbecreatedandinjectedifthisattributeisattachedtoasetter.ThenewobjectwillbeaddedtotheWorkItem’sItemscollection.
1.ComponentDependency(stringID)这一attribute可以被用于注入任何已经在workitem的itemscollection里的对象,然而,因为我们能拥有同一种类型的多种对象,我们必须知道我们需要注入的对象的id,它是一个字符串,我们可以给我们加入到collection里的object加一个id,如果我们不明确加一个id,cab会随机分配一个guid作为id,注意如果这个对象不存在于合适的itemcollection里,当我们试着给他加注入的时候,CAB就会报一个DependencyMissingException的错误出来。2.ServiceDependency我们已经看到了这个attribute了,使用这个attribute的时候,该对象必须在workitem的servicecollection里才能被注入,servicecollection只能包含给定类型的一个对象,意味着这不需要id,我将在part6继续讨论services3.CreateNew如果这个attribute被加在了setter上的时候,一个适合类型的新对象会被创建并且injected,新对象会被加入的workitem的itemcollection里。Asusualthisisbestseenwithanexample.ExampleWesetupaCABprojectwithtwocomponentclasses.Component1isjustanemptyclass,whilstComponent2hastwoprivateComponent1membervariablesthatwillbeinjected.Onewillbeinjectedbyname(andsoneedstobecreatedandaddedtotheWorkItem’sItemscollectionpriortoinjection).Onewillbeinjectedbybeingcreated:我们新建了一个cab的项目,该项目里有两个component的类,component1是一个空的class,component2有两个会被注入的私有的component1的变量,一个会被通过已有的名字注入,另一个则是通过createnew注入。
publicclassComponent2
{
privateComponent1component11;
[ComponentDependency("FirstComponent1")]
publicComponent1Component11
{
set
{
component11=value;
}
}
privateComponent1component12;
[CreateNew]
publicComponent1Component12
{
set
{
component12=value;
}
}
}


TousethisweputthefollowingcodeintheAfterShellCreatedmethodofourFormShellApplicationclass:
protectedoverridevoidAfterShellCreated()
{
RootWorkItem.Items.AddNew<Component1>("FirstComponent1");
Component2component2=newComponent2();
RootWorkItem.Items.Add(component2);
DisplayRootItemsCollection();
}
NoticethesyntaxoftheAddNewcommandfortheItemscollection.It’sagenericmethod.Rememberthatagenericissimplyawayofprovidingatype(inthiscaseaclass)atruntime.Hereweareprovidingthetype“Component1”totheAddNewgenericmethod.Agenericmethodcandoanythingitlikeswiththetypeprovided.HereAddNewwillinstantiatethattypeandaddittotheitemscollection.注意到addnew命令的语法,这是一个泛型的方法,记住泛型是一种简单的方法在运行时提供类型,现在我们提供了component1,将其加入到addnew的泛型方法里,一个泛型方法可以做任何给定类型的事,在这里,addnew会实例化这个类型,并且将它加到我们的itemscollection里。Asyoucansee,wecreateaComponent1objectwithID“FirstComponent1”andaddittotheItemscollection.WethencreateaComponent2objectusingthe‘new’keyword.WewouldusuallydothisusingAddNew,butIwanttodemonstratethatwedon’thavetodothis.NextweaddtheComponent2objecttotheItemscollection.正如你所看到的,我们通过id”firstcomponent1“创建了一个component1的对象,并且将它加入到我们的itemscollection里,然后我们通过new创建了component2对象,我们应该使用addnew方法,但是我只是想说明我们未必一定要这么做,然后我们将component2加入到这个items的collection里。Atthispointthe“FirstComponent1”objectwillbeinjectedintocomponent2inthesettermarkedwiththe“ComponentDependency”attribute.AlsoanotherComponent1objectwillbecreatedandinjectedintocomponent2inthesettermarkedwiththe“CreateNew”attribute.在这里“firstcomponent1“对象会被通过拥有“ComponentDependency”attribute的setter注入到component2中,同时component1对象会被创建并且通过拥有“CreateNew”的attribute注入到component2中。FinallyinthiscodewecallaroutinecalledDisplayRootItemsCollection:
privatevoidDisplayRootItemsCollection()
{
System.Diagnostics.Debug.WriteLine("ITEMS:");
Microsoft.Practices.CompositeUI.Collections.ManagedObjectCollection<object>coll=RootWorkItem.Items;
foreach(System.Collections.Generic.KeyValuePair<string,object>oincoll)
{
System.Diagnostics.Debug.WriteLine(o.ToString());
}
}
ThisjustdumpsoutalltheobjectsintheItemscollectiontothedebugwindow.Theresultsareasbelow:ITEMS:
[4e0f206b-b27e-4017-a1b2-862f952686da,Microsoft.Practices.CompositeUI.State]
[14a0b6a2-12a4-4904-8148-c65802af763d,Shell.Form1,Text:Form1]
[FirstComponent1,Shell.Component1]
[4c7e0a20-90b7-42c6-8912-44ecba40523f,Shell.Component2]
[c40a4626-47e7-4324-876a-6bf0bf99c754,Shell.Component1]Asyoucanseewe’vegottwoComponent1itemsasexpected,onewithID“FirstComponent1”andonewithIDaGUID.AndwehaveoneComponent2itemasexpected.WecanalsoseethattheshellformisaddedtotheItemscollection,aswellasaStateobject.Thecodeforthisisavailable,andifyousingle-stepthroughityoucanseethetwoComponent1objectsbeinginjectedintocomponent2.正如你所看到的,我们得到了我们期望得到的两个component1,一个的id是“FirstComponent1”,另一个是guid,我们还拥有我们所期待的component2,我们还能看到shellform和stateobject,如果你单步调试它,你会看到这两个component1被注入到了component2里。WhereWasAllThisintheOriginalExample?NotethatintheoriginalexampleinthisarticletherootWorkItemwasinjectedintoaModuleInitclassapparentlywithouttheModuleInitclassbeingaddedtoanyWorkItem.ThisseemstocontradicttheparagraphsabovethatsaythatwecanonlyinjectintoobjectsthatareputintoWorkItems.However,theCABframeworkautomaticallyaddsModuleInitclassesintotherootWorkItemwhenitcreatesamodule,sowedon’tneedtoexplicitlyaddthemourselvesforthedependencyinjectiontowork.注意到在这篇文章的第一个例子里,在ModuleInitclass没有被加入到任何workitem的前提下rootworkitmen被注入到一个ModuleInitclass里,这似乎违背了上面那段话所说的,我们只能注入被加入到workitems里的objects,然而,当module被创建的时候,cabframework自动的把ModuleInitclasses加入到rootworkitem,所以我们没必要显式的再加入他。Futhermore,therootWorkItemthatwasinjectedasaServiceDependencyeventhoughithadnotbeenexplicitlyaddedtoanyServicescollection.Againthisseemstocontradictthestatementsabovethatanyobjectbeinginjectedmustbeinanappropriatecollection.ButthecodeworksbecauseanyWorkItemisautomaticallyamemberofitsownServicescollection.此外,这个rootworkitem会被作为servicedependency注入,即使它没有被显性的加入到servicecollection里,再次说明,这似乎违法了上面所声明的任何被注入的对象必须被加入到一个合适的collection里,但是这代码奏效是因为这workitem会自动的成为servicecollection的一员。Youcanseethisifyoudownloadandrunthisexample.ItisanextensionoftheoriginalexamplethatallowsyoutooutputboththeItemscollectionandtheServicescollectiontotheoutputwindowviaamenuoption.Ifyoudothisaftertheapplicationhasloadedyougettheoutputbelow:连接里的例子是原来那个例子的扩展,它允许你同属输出itemcollection和servicescollection到输出窗体的菜单选项里,如果你在程序启动后做这些,你将得到如下:ITEMS:
[336ad842-e365-47dd-8a52-215b951ff2d1,Microsoft.Practices.CompositeUI.State]
[185a6eb5-3685-4fa7-a6ee-fc350c7e75c4,Shell.Form1,Text:Form1]
[10d63e89-4af8-4b0d-919f-565a8a952aa9,Shell.MyComponent]
[Shell,Shell.Form1,Text:Form1]
[21ac50d7-3f22-4560-a433-610da21c23ab,Blue.BlueModuleInit]
[e66dee6e-48fb-47f0-b48e-b0eebbf4e31b,Red.RedModuleInit]
SERVICES:
[Microsoft.Practices.CompositeUI.WorkItem,Microsoft.Practices.CompositeUI.WorkItem]
…(Completelisttruncatedtosavespace)YoucanseethatboththeBlueModuleInitandRedModuleInitobjectsareintheItemscollectioninspiteofnotbeingexplicitlyaddedbyusercode,andtheWorkItemisintheServicescollection.你可以看到BlueModuleInit和RedModuleInit都在itemcollection里尽管它们没有被显式地加入到代码中,且workitem也在Servicescollection里ObjectBuilderTounderstandandusetheCompositeApplicationBlockyoudon’tneedtounderstandindetailitsunderlyingcode.It’sintendedtobeusedasaframeworkafterall.However,it’susefultoknowthatthedependencyinjectionhereisalldonebytheObjectBuildercomponent.为了理解并使用CompositeApplicationBlock你没必要理解最底层代码的细节,毕竟那是framework,然而,知道依赖注入是由ObjectBuilder完成的这很有用。WhenwecallAddNeworAddonacollectionofaWorkItemit’stheObjectBuilderthatlooksatthedependencyattributesontheclasswe’readdingandinjectstheappropriateobjects.当我们调用AddNew或者Add方法的时候,那是ObjectBuilder在寻找依赖注入的属性,在这个类里我们加入并且注入适当的对象。TheObjectBuilderisa‘builder’intheclassicdesignpatternssense.Thebuilderpattern‘separatestheconstructionofacomplexobjectfromitsrepresentationsothatthesameconstructionprocesscancreatedifferentrepresentations’.ObjectBuilder是builderpattern设计模式里的builder类,这一模式将构造和复杂对象分离开,如此同一构造顺序可以创建出不同的表现。Notethatthispatternisoftencalleda‘factorypattern’,althoughfactoriesintheGangofFour‘DesignPatterns’bookareslightlydifferentthings(we’renotcreatingfamiliesofobjects(AbstractFactory)or‘letting‘thesubclassesdecidewhichclasstoinstantiate’(FactoryMethod)).注意这一模式经常被叫做‘factorypattern’虽然在GangofFour的设计模式这本书里factories是另外一回事。WorkItemsinaHierarchyandDependencyInjectionofItemsAsdiscussedpreviously,oneofthestrengthsofWorkItemsisthatmultipleinstancescanbeinstantiatedindifferentmodules,andtheycanallbearrangedinahierarchy.ThisisbecauseeachWorkItemhasaWorkItemscollection.However,youshouldbeawarethatdependencyinjectiononlyworksforitemsinthecurrentWorkItem.IfyouattempttoinjectanobjectinadifferentWorkIteminthehierarchyintoanobjectinyourWorkItemyouwillgetaDependencyMissingException.像我们之前讨论过的,WorkItems的一大优势在于复数的实例可以在不同的modules里被实例化,而且他们能被安排成树状结构,这是因为每一个workitem都有一个workitemscollection,然而,你需要知道依赖注入只能在当前的workitem中奏效,如果你尝试着注入一个object到不同的workitem里,你会得到如下错误:DependencyMissingExceptionWecanseethisbymodifyingtheAfterShellCreatedeventofourFormShellApplicationintheexampleusingComponent1andComponent2above:我们可以通过修改上面的代码来看:
WorkItemtestWorkItem=null;
protectedoverridevoidAfterShellCreated()
{
testWorkItem=RootWorkItem.WorkItems.AddNew<WorkItem>();
RootWorkItem.Items.AddNew<Component1>("FirstComponent1");
//ThenextlinethrowsanexceptionasthetestWorkItem
//containerdoesn'tknowaboutFirstComponent1,andComponent2
//isaskingforittobeinjected.
testWorkItem.Items.AddNew<Component2>();
DisplayRootItemsCollection();
}
HereweaddanewWorkItemtoourRootWorkItem.WeaddaninstanceofComponent1withID“FirstComponent1”toourRootWorkItemasbefore.ThenweaddaninstanceofComponent2toourtestWorkItem.现在我们加入一个WorkItem到RootWorkItem,我们加入Component1withID“FirstComponent1”的实例到我们的RootWorkItem里,然后我们加入Component2的实例到testWorkItem。RememberthatComponent2asksforaComponent1objectwithID“FirstComponent1”tobeinjectedwhenitiscreated.BecausethetestWorkItemknowsnothingaboutsuchanobjectwegetanexceptionthrown.记住当Component2被创建的时候,它寻找id为”FirstComponent1“的Component1,因为testWorkItem对”FirstComponent1“的Component1一无所知,所以就报了这个错。WecanfixthecodebyaddingourComponent1intothetestWorkIteminsteadoftheRootWorkItem:我们可以这样修复它:
testWorkItem.Items.AddNew<Component1>("FirstComponent1");
Thecodeforthisexampleisavailable.WorkItemsinaHierarchyandDependencyInjectionofServicesServicesbehavedifferentlytotheexamplegivenabove.Services的表现则另有不同WecanmakeComponent1aservicebyaddingittotheServicescollectionoftheRootWorkIteminsteadoftheItemscollection,andtellingComponent2it’saServiceDependencyandnotaComponentDependency.Thenthecodewillwork.ThisisbecausetheCABincludesaservicelocatorthatlooksinallparentWorkItemsofthecurrentWorkItemtoseeifagivenserviceisavailable.Iwilldiscussthisinmoredetailinpart6.我们可以通过将Component1加入到RootWorkItem的Servicescollection而不是Itemscollection让其变成service,并且告诉Component2那是一个ServiceDependency而不是ComponentDependency,然后这代码就能奏效了,这是因为CAB会去找当前WorkItem的所有parentWorkItems去看看有没有sevice可用,我们将在第part6里更多的讨论ConclusionDependencyinjectionintheCABisapowerfultool.Itenablesustosharecodebetweenmodulesinaloosely-coupledway.Inpart6ofthisseriesofarticlesIdiscusshowwecanusetheCABtodoconstructorinjection.Part7oftheserieswillinvestigatetheServicescollectionofaWorkIteminsomedetail.CAB的Dependencyinjection是一个非常强大的工具,它能使我们在不同modulesshare代码。在part6,我将会讨论我们如何使用cab的结构注入,Part7会讨论Servicescollection
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐