StructureMap-䜜業のクむックリファレンス1/3

今日は、StructureMap IoCコンテナヌに぀いお説明したすこれは叀い公匏ドキュメントの翻蚳ではありたせん。Unityよりもずっず気に入っおいたす。 正盎なずころ、Unityずの関係は最初からうたくいきたせんでした。コヌドの構成ファむルたたはコヌドに200の重芁な構成行がありたした。 悲しいこずに぀いお話したしょう。



StructureMapは、他のDI \ IoC実装よりも䟿利なように思えただけでなく、GoogleでStructureMapずUnityを入力するだけで、人々がStructureMapが最も䟿利で柔軟で自然な仕事であるこずを明確に議論し、実蚌するリンク集を入手できたす。



1、2、3をリンクしたす。 さらに、StructureMapは非垞に高速です。

以䞋に、フレヌムワヌクを比范する非垞に興味深い資料のコレクションを瀺したすhttp://www.sturmnet.org/blog/2010/03/04/poll-results-ioc-containers-for-net



このようなコンテナをプロゞェクトで䜿甚する必芁があるかどうか、および独自の実装を䜜成する䟡倀があるかどうかに぀いおの議論は省略できるず思いたす。 最初の私の実践では、胜力ず利䟿性の点で著しく劣る自己蚘述型の実装があったこずがありたしたが、それらは特定のタスクを解決し、それで十分でした。 プロゞェクトの開発に䌎い、すべおを他の技術に移行する時間が䞍足しおいたした。 その埌、Unity、Unityがありたしたが、結局、StructureMapを詊しおみる必芁があり、䞀床も埌悔しなかったずいう結論に達したした。



私の意芋では、StructureMapの利点は䜕ですか



StructureMapにはただ倚くの興味深く有甚なものがありたすが、それらをプラスに垰するのは間違っおいたす。人生を楜にするだけの楜しい远加ず呌ぶ方が良いでしょう。



フォロヌアップ資料の抂芁は次のずおりです。





StructureMapをむンストヌルする



NuGetを䜿甚しお、StructureMapをアプリケヌションにむンストヌルするこずをお勧めしたす。 パッケヌゞマネヌゞャヌコン゜ヌルinstall-Package StructureMapの1぀のコマンド、たたはりィザヌドを䜿甚した怜玢ずむンストヌルが、それを取埗する最も簡単な方法です。 ただし、必芁に応じお、公匏ペヌゞhttp://github.com/structuremap/structuremap/downloadsからプロゞェクトをダりンロヌドできたす。





登録



おそらく、IoCコンテナにずっお最も重芁なアクションは登録です。 それは、それがいかに䟿利で理解しやすいか、人々がそれを䜿甚するかどうか、そしおツヌルの䞍適切な䜿甚の可胜性に䟝存したす。



著者は、DSLをできるだけ広く䜿甚し、接続文字列、URL、ファむルパス、およびその他すべおを同じように個別に蚭定する必芁がある堎合にのみ、構成ファむルに頌るこずをお勧めしたす。



最も単玔なものから始めたしょう。デフォルトのコンストラクタヌでクラスを登録したす。



このような単玔なクラスセットがあるずしたす。

public interface IClass {} public interface IClass1 : IClass {} public interface IClass2 : IClass {} public class Class1 : IClass1 {} public class Class2 : IClass2 {}
      
      





これたでのずころ、このセットが可胜性を実蚌する䞻なものになりたす。 しかし、心配しないでください。これ以䞊のクラスず接続はより難しくなりたす。そのようなクラスでもあたり衚瀺されないからです。





ベヌス



登録は、 Containerを䜿甚しお、静的ObjectFactoryクラスを䜿甚しお、たたはRegistryクラスを䜿甚しお可胜です。 これらすべおのオブゞェクトを䜿甚しお、登録を埐々に怜蚎しおください。 登録の䞻なクラスはレゞストリであり、残りのクラスは䟿宜䞊、その機胜をスロヌしたす。



静的ObjectFactoryクラスに登録したす。

 public class RegisterByObjectFactory { public RegisterByObjectFactory() { ObjectFactory.Initialize(x => { x.For<IClass1>().Use<Class1>(); x.For<IClass2>().Use<Class2>(); }); } }
      
      





すべおがDSLおよびラムダ匏を䜿甚しお行われたす。 DSL自䜓は非垞に簡朔で理解しやすく、結果のコヌドは意味のある衚珟に簡単に折りたたたれたす。 この堎合、 IClass1 むンタヌフェむスに Class1を䜿甚 する 必芁があるこずを簡単に 理解 できたす 。



オブゞェクトの取埗は、次の方法で行うこずができたすが、盎感的でもありたす。

 private static string ObjectFactoryExample() { new RegisterByObjectFactory(); var class1Inst = ObjectFactory.GetInstance<IClass1>(); var class2Inst = ObjectFactory.GetInstance<IClass2>(); return ObjectFactory.WhatDoIHave(); }
      
      





この堎合、むンタヌフェむスでGetInstanceオブゞェクトを取埗するメむンメ゜ッド。 さらに、完成したオブゞェクトを取埗するさたざたな方法を怜蚎したす。 メ゜ッドは、メ゜ッドから取埗した文字列を返すこずがわかりたす。この名前は、発話名WhatDoIHaveを持ちたす。 この方法を䜿甚するず、コンテナの内郚を蚺断し、䜕が、どのように、どこに登録されおいるかを確認できたす。



長い間、フレヌムワヌクの䜜者は圌の子孫に関連しおコンテナずいう甚語を受け入れるこずができなかったため、次のメ゜ッドは長い間隠されおいたしたが、その埌の実装でのみ、静的クラスの背埌で内郚で実装されたように、自然な登録コヌスが開かれたした。 だから

 public class RegisterByContainer { public IContainer Container; public RegisterByContainer() { Container = new Container(x => { x.For<IClass1>().Use<Class1>(); x.For<IClass2>().Use<Class2>(); }); } }
      
      





䞀芋、すべおが同じで、ラムダが同じですが、今床はクラスを䜜成し、それを倖郚に枡し、それによっおコンテナにアクセスしたす。 ぀たり 繰り返したすが、ObjectFactoryはContainerクラスの静的ラッパヌクラスにすぎたせん。



オブゞェクトの取埗も同じシナリオに埓いたす。

 private static string ContainerExample() { var container = new RegisterByContainer().Container; var class1Inst = container.GetInstance<IClass1>(); var class2Inst = container.GetInstance<IClass2>(); return container.WhatDoIHave(); }
      
      





行の次のオブゞェクトはRegistryです。 実際、以前はすべお間接的に呌び出しおいたした。 倉曎のために、特定のクラスを登録したす。

 public class RegisterByRegister { public IContainer Container; public RegisterByRegister() { var registry = new Registry(); registry.ForConcreteType<Class1>(); registry.ForConcreteType<Class2>(); Container = new Container(x => x.AddRegistry(registry)); } }
      
      





この堎合、 ForConcreteTypeメ゜ッドが䜿甚されたす。これはの同矩語です。 < T>の堎合。 < T>を 䜿甚したす。 たた、Registryクラスをサブコンテナずしお䜿甚し、アセンブルしおから、1぀のコンテナ内のアセンブリに転送できるこずもわかりたす。 この堎合、䜜成時のレゞストリの远加が瀺されおいたすが、䜕も曞くこずを劚げるものはありたせん。

 Container = new Container(); Container.Configure(x => x.AddRegistry(registry));
      
      





「具䜓的な」クラスを読むこずは、通垞ず倉わりたせん。

 private static string ConcreteClassExample() { var container = new RegisterByRegister().Container; var class1Inst = container.GetInstance<Class1>(); var class2Inst = container.GetInstance<Class2>(); return container.WhatDoIHave(); }
      
      







プロフィヌル



StructureMapでは、名前付きプロファむルを䜿甚しおクラスマッピングをグルヌプ化できたす。 ぀たり マッピングクラスをすばやく切り替えるこずができたす。

 public class RegisteringProfiles { public IContainer Container; public RegisteringProfiles() { var registry = new Registry(); registry.Profile("p1", x => x.For<IClass>().Use<Class1>()); registry.Profile("p2", x => x.For<IClass>().Use<Class2>()); Container = new Container(x => x.AddRegistry(registry)); } }
      
      





ここでは、クラスClass1ずClass2が共通むンタヌフェヌスによっお登録されおいたすが、異なるプロファむルにあるこずに泚意する䟡倀がありたす。 必芁なクラスを取埗するには、プロファむルの名前を取埗するSetDefaultProfileメ゜ッドを䜿甚しお、コンテナ内のプロファむルを切り替える必芁がありたす。

 private static string ProfilesExample() { var container = new RegisteringProfiles().Container; container.SetDefaultsToProfile("p1"); var class1Inst = container.GetInstance<IClass>(); container.SetDefaultsToProfile("p2"); var class2Inst = container.GetInstance<IClass>(); return container.WhatDoIHave(); }
      
      





プロファむル名には文字列倉数のみを䜿甚できたすが、これはもはや倧きな問題ではありたせん。 ぀たり、実際には、䟋のように線を開いおプロファむル名を曞くべきではありたせん。 カルマに有害です



アクティブなプロファむルを蚭定した埌、通垞どおりコンテナを操䜜できたす。 その結果、同じ行を実行するず、 container.GetInstance <IClass>; 異なるクラスを取埗したす。





プラグむン



共通むンタヌフェヌスを䜿甚しお特定のクラスを取埗する問題を解決する別の方法がありたす。これは名前付きプラグむンです。



甚語に぀いお少し。 IntelliSenseずここの少しでは、プラグむン、PluginTypeおよびPluggedTypeずいう甚語を芋぀けるこずができたす。䞀般的に、これは取埗したいタむプを意味したす 。 ぀たり 前述のすべおの䟋で、IClassはPluginTypeず呌ばれ、Class1たたはClass2はPluggedTypeず呌ばれたす。

 public class RegisterAsPlugin { public IContainer Container; public RegisterAsPlugin() { Container = new Container(x => { x.For<IClass>().Use<Class1>().Named("Class1"); x.For<IClass>().Use<Class2>().Named("Class2"); }); } }
      
      





䟋ずしお、共通のむンタヌフェヌスでクラスを登録するこずがわかりたすが、同時に特定の名前を付けたす。 Namedメ゜ッドを䜿甚しお、特定のタむプを簡単に照䌚できるようになりたした。

 private static string PluginExample() { var container = new RegisterAsPlugin().Container; var class1Inst = container.GetInstance<IClass>("Class1"); var class2Inst = container.GetInstance<IClass>("Class2"); var instanceDef = container.GetInstance<IClass>(); return container.WhatDoIHave(); }
      
      





この䟋は、コンテナヌにアクセスしお、共通むンタヌフェヌスで特定のタむプを取埗する方法を瀺しおいたす。 ただし、ここで同時に質問を提起したす。プラグむン名を指定せずに共通のむンタヌフェむスでGetInstanceメ゜ッドを呌び出そうずするずどうなりたすか



デフォルトの動䜜は、「誰が最埌、぀たりパパ」ずいう蚀い方に埓いたす 。 この堎合、 Class2クラスのむンスタンスはinstanceDef倉数に入りたす。 ただし、デフォルトクラスを明瀺的に定矩できたす。 これを行うには、プラグむンの登録のわずかに異なる圢匏を䜿甚したす。

 public class RegisterAsPluginWithDefault { public IContainer Container; public RegisterAsPluginWithDefault() { Container = new Container(x => x.For<IClass>() .AddInstances(i => { i.Type(typeof (Class1)).Named("Class1"); i.Type(typeof (Class2)).Named("Class2"); }) .Use(new Class1()) ); } }
      
      





たた、この䟋はそれ自䜓を説明しおいるず蚀えたす。 読んだ堎合、文字通りリテラルになりたす IClass むンタヌフェむスには 、 Class1ずいう名前のclass1 実装を远加 し、 Class2 ずいう名前の Class2 を 远加し たす Class1を 䜿甚したす この堎合、非垞に特定のクラスですが、前の䟋で。 >。



この堎合、デフォルトのむンタヌフェヌスに䜿甚されるタむプを䌝えるのはUseメ゜ッドです。 ここで次のコヌドを実行するず

 var instanceDef = container.GetInstance<IClass>();
      
      





次に、クラスClass1のむンスタンスを取埗したす。



Useは既にデフォルトのタむプを公開しおいたす。





スキャン



論理的な継続は、コンテナ内の型の怜玢ず自動登録です。 共通のむンタヌフェヌスから2぀のクラスを継承するのではなく、50を想像しおください これらすべおの登録ず䟝存関係を自分の手で満たすのは非垞に悲しく退屈です。 このような堎合、StructureMapには、関心のあるアセンブリたたはフォルダヌを実行しお適切なオブゞェクトを登録するScanメ゜ッドがありたす。 したがっお、アプリケヌションにプラグむンの構造を実装し、䜕らかの方法でMEFず競合したり、MEFず眮き換えるこずも可胜です。



Scanメ゜ッドがタむプを芋぀けお登録するには、いく぀かの条件が満たされおいる必芁がありたす。



スキャン方法ず動䜜はオヌバヌラむドされる堎合がありたすが、珟時点ではこれは考慮されたせん。



スキャンするアセンブリをいく぀かの方法で指定できたす。



実隓的なアセンブリを指摘した埌、さたざたなパラメヌタヌで型を含める/陀倖する方法を䜿甚しお、むンポヌトプロセスをより詳现に構成できたす。 詳现に぀いおは、 ドキュメントを参照するこずをお勧めしたす 。 それは時代遅れですが、可胜性の䞀般的なアむデアを提䟛したす。



それでは、より簡単な䟋を芋おみたしょう。

 public class RegisterByScan { public IContainer Container; public RegisterByScan() { Container = new Container(x => x.Scan(s => { s.AddAllTypesOf(typeof (IClass)); s.AssembliesFromPath("."); s.WithDefaultConventions(); s.LookForRegistries(); })); } }
      
      





このクラスでは、アプリケヌションフォルダヌからIClassむンタヌフェむスを実装するすべおの型をむンポヌトするこずを蚀いたす。デフォルトの芏則に埓っおください。 最埌の行は、怜玢を開始するコマンドです。 以前は、明瀺的な指瀺なしにすべおが機胜しおいたした。 ただし、LookForRegistriesメ゜ッドを明確に定矩する必芁がありたす。



メ゜ッドが機胜するず、コンテナで怜出および登録された内容を確認できたす。

 private static string RegisterByScanExample() { var container = new RegisterByScan().Container; var instances = container.GetAllInstances<IClass>(); return container.WhatDoIHave(); }
      
      





Get All Instancesメ゜ッドが呌び出されおいるこずに泚意しおください。 登録されたクラスから特定のクラスを取埗するメ゜ッドを呌び出すず、StructureMapは「デフォルトで」返すクラスを認識しないため、゚ラヌが発生したす。



正盎なずころ、このような実装では、スキャンコマンドの結果を䜿甚するこずはできたせん。 すべおがうたくなり、芋぀かったクラスを名前で参照できるようにするには、スキャンコヌドを少し曞き換える必芁がありたす。

 public class RegisterByScanWithNaming { public IContainer Container; public RegisterByScanWithNaming() { Container = new Container(x => x.Scan(s => { s.AddAllTypesOf(typeof (IClass)).NameBy(t => t.Name); s.AssembliesFromPath("."); s.WithDefaultConventions(); s.LookForRegistries(); })); } }
      
      





すべおのクラスを名前で登録する必芁があるずいう明確なルヌルがAddAllTypesOfメ゜ッドに远加されたした。 この倉曎埌、特定のタむプを操䜜できたす。

 var instance = container.GetInstance<IClass>("Class1");
      
      







実装



コンテナの操䜜䞭に、デフォルトで返されるタむプをオヌバヌラむドできたす。 これは䞻にテストで䜿甚されたす。 仕事のデモンストレヌション

 private static string InjectExample() { var container = new RegisterAsPluginWithDefault().Container; var instance1 = container.GetInstance<IClass>("Class1"); var instance2 = container.GetInstance<IClass>("Class2"); var class1Inst = container.GetInstance<IClass>(); container.Inject(typeof (IClass), new Class2()); var class2Inst = container.GetInstance<IClass>(); return container.WhatDoIHave(); }
      
      





以前に、デフォルトのClass1クラスを返すRegisterAsPluginWithDefaultクラスを宣蚀したした。 Injectメ゜ッドを䜿甚するず、戻り倀の型をオヌバヌラむドできたす。プラグむンの型ず新しいクラスを指定するだけです。



これらの䟋は、クラス自䜓が単玔な堎合の登録の䞀般原則に基づいおいたす。 次のトピックでは、パラメヌタヌを持぀コンストラクタヌを持぀クラスをどのように扱うかを怜蚎したす。



継続する。



All Articles