LIGHT11LIGHT11読者になるLIGHT112021-02-01【Unity】DIコンテナVContainerの使い方まとめUnityUnityでDIコンテナVContainerの使う方法についてまとめました。1.4.0はじめにVContainerはUnity(ゲームエンジンの方)用のDIコンテナです。github.com機能が多すぎず少なすぎず、導入も簡単なのでとても使いやすいDIコンテナになっています。程よい大きさのDIコンテナにはとても価値があると思います。本記事ではこのVContainerの使い方についてまとめます。英語に抵抗ない方はこちらを参照していただくのが良いかと思います。vcontainer.hadashikick.jpなお本記事ではDIの基礎知識については前提知識とし、記事内では説明しませんのでご了承ください。インストールインストールはmanifest.jsonに以下の一行を追加することで行います。Containerとして使ってみるさてそれではまずVContainerをServiceCollectionのようなシンプルなIoCコンテナとして使ってみます。準備として、以下のようにIFooServiceを実装したFooServiceとIBarServiceを実装したBarServiceを用意します。BarServiceはそのコンストラクタでIFooServiceを受け取ります。}}これらの依存関係をVContainerで解決するには以下のように実装します。}}ServiceCollectionとの対比としては、ContainerBuilderがServiceCollection相当のもの、IObjectResolverがServiceProvider相当のものという位置づけになります。VContainerの基本的な使い方さてVContainerでは前節のような、ContainerBuilderを生成してObjectResolverをビルドしたり、サービスが有効期間を抜けたらDisposeするような処理をライブラリ側でサポートしてくれます。以下ではこの方法についてまとめます。LifetimeScopeというVContainerのクラスを継承したクラスを定義します。Configure()メソッドをオーバーライドして引数のbuilderに前節のようにサービスを追加していきます。}}次にエントリポイントを作っていきます。適当にBarServiceを使用するクラスを作っておきます。VContainerのIInitializableインターフェースを実装しておきます。}}最後にこのエントリポイントを先ほどのIContainerBuilderにRegisterEntryPoint()メソッドで登録します。次にそれに依存しているBarServiceとFooServiceがインスタンス化され依存性注入されます。EntryPointのInitialize()が呼ばれてエントリポイントが初期化されます。(FooServiceとログ出力されます)またGameLifetimeScopeがDestroyされた際には生成された各インスタンスのIDisposable.Dispose()が(実装されていれば)呼ばれます。このようにIContainerBuilderに登録したエントリポイントを起点にして処理を進めていくのが基本的な使い方となります。IInitializable以外のライフサイクルイベント前節にはEntryPointにIInitializableを実装しましたが、ライフサイクルイベントは他にも存在します。以下に、Unityのイベントとそれに相当するVContainerのインターフェースを表します。IPostLateTickable生存期間を管理するLifetime次に生存期間の管理についてまとめます。以下のように、IContainerBuilder.Register()を行う際にはその引数にLifetimeを指定します。builder.Register<FooService>(Lifetime.Singleton);上記のようにLifetime.Singletonとした場合、FooServiceは最初に依存性注入される際にインスタンス化され、それ以降は何度注入されても同じインスタンスが使いまわされます。親と子で同じ型がRegisterされていた場合にはそれぞれ別のインスタンスが生成されます。所属するLifetimeScopeがDestroyされたタイミングでIDisposable.Dispose()が呼ばれます。次にLifetime.Transientです。builder.Register<FooService>(Lifetime.Transient);これは注入されるたびに新しいインスタンスが生成されます。生存期間がLifetimeScopeに依存しないためLifetimeScopeがDestroyされてもIDisposable.Dispose()は呼ばれません。最後にLifetime.Scopedです。builder.Register<FooService>(Lifetime.Scoped);これは依存性注入される際に、同じLifetimeScope内に既に作られたインスタンスがあったらそれを使い、なければインスタンス化します。親のLifetimeScopeで作られたインスタンスと同じ型のインスタンスが子のLifetimeScopeで注入される際には新しく作られます。所属するLifetimeScopeがDestroyされたタイミングでIDisposable.Dispose()が呼ばれます。LifetimeScopeの親子関係の設定方法さて次にLifetimeScopeの親子関係を設定する方法についてまとめます。LifetimeScopeのInspectorから最も手軽な方法はLifetimeScopeのInspectorから設定する方法です。Parentの項目からLifetimeScopeのサブクラスの型が一覧化されるので、親にしたい型を選択します。LifetimeScopeのインスペクタから親子関係を設定あとは親がインスタンス化されている状態で子をインスタンス化すれば親子関係が構築されます。子のシーンやPrefabを読みこんで設定する次にLifetimeScopeがアタッチされたGameObjectを持つシーンやPrefabを読み込んで子として設定する方法を紹介します。これを行うには以下のように、子を読み込む前にLifetimeScope.EnqueueParent()に親を渡しておきます。ここで子のシーンを読み込んだりPrefabをInstantiateしたりする}usingのスコープ内でシーンやPrefabを読み込めば自動的に親子関係が構築されます。そのまま子のIContainerBuilderを操作したい場合にはLifetimeScope.Enqueue()を使います。builder.Register<IFooService>(Lifetime.Scoped);})){}なおPrefabを子とする場合には以下のようにLifetimeScope.CreateChildFromPrefab()を使って生成することもできます。builder.Register<IFooService>(Lifetime.Scoped);});コードベースで子を生成するPrefabやシーンにLifetimeScopeをアタッチするのではなくコードから生成する場合には以下のようにLifetimeScope.CreateChild()を使います。破棄childScope.Dispose();IContainerBuilderに登録を行う方法まとめ次にIContainerBuilderに登録する際のいろんなやり方をまとめます。これに関しては以下のコードにコメントの形でまとめておきます。依存性を注入する方法についてまとめます。基本的なインジェクションVContainerでは基本的な依存性注入の方法としてコンストラクタインジェクションとメソッドインジェクション、プロパティ/フィールドインジェクションが用意されています。使い方としては以下のようにそれぞれInjectアトリビュートを付けるだけです。今、IFooServiceを実装したインスタンスが複数回Registerされているとします。FooService());これらのインスタンスをすべて注入したい場合には、注入される側の引数をIEnuerable型にします。}}これですべてのインスタンスを注入できます。IEnumerableではなくIReadOnlyListでもOKです。IObjectResolverを注入する以下のようにIObjectResolverを注入することもできます。1はてなブログをはじめよう!halya_11さんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。