Doinject をはじめよう
Unity Package Manager でインストール
Unity Package Manager からインストールすることができます。
MewCore のインストール
まず、依存ライブラリとなる、MewCore パッケージをインストールしてください。
Unity のメニューから を選択します。
+ ボタンをクリックし、 Add package from git URL... を選択します。
以下を入力し、 Add をクリックします。
https://github.com/mewlist/MewCore.gitgit@github.com:mewlist/MewCore.git
Doinject のインストール
次に、Doinject パッケージをインストールします。
Unity のメニューから を選択します。
+ ボタンをクリックし、 Add package from git URL... を選択します。
以下を入力し、 Add をクリックします。
https://github.com/mewlist/Doinject.gitgit@github.com:mewlist/Doinject.git
エントリポイントを決める
最初にすべきことは、DIフレームワークを適用したいシーンを開き、ヒエラルキに SceneContext コンポーネントを配置することです。
ヒエラルキビューで右クリックし、 > メニューを選択します。

配置されたシーンコンテクスト

これで、このシーンは DI フレームワークの実行環境として機能するようになりました。 試しに一度再生してみてください。

シーンが再生されると、このように各種ローダーが生成されます。
初めてのインジェクション
DIコンテナにインスタンスを登録して、インジェクションを行ってみましょう。 インスタンスの登録(バインディングと言います)はインストーラというコンポーネントから行います。
注入ポイントについて
- DIコンテナに登録された型を、特定のインスタンスへ注入するためには、以下方法があります
コンストラクタインジェクション
メソッドインジェクション
フィールドインジェクション
プロパティインジェクション
コンストラクタインジェクションは、DIコンテナを通じてインスタンスを生成する際に自動的に行われます。 メソッドインジェクションは、[Inject] 属性をつけたメソッドを呼び出すことで行われます。 プロパティインジェクション・フィールドインジェクションは、[Inject] 属性をつけたフィールド・プロパティに対してインスタンスを注入します。
MonoBehaviour を継承したコンポーネントの場合、コンストラクタインジェクションは使えません。 コンポーネントの生成は、Unity が行うため、明示的にコンストラクタを呼び出せないためです。 そのため、メソッドインジェクション・フィールドインジェクション・プロパティインジェクションを使う必要があります。
コンストラクタインジェクション
メソッドインジェクション
OnInjected() コールバックについて
[OnInjected] 属性が付与されたメソッドは(引数なし・public) は、 インスタンスの注入が完了したタイミングで、自動的に呼び出されます。 Task, ValueTask の戻り値を持つ非同期関数であっても問題ありません。
特に、MonoBehaviour を継承したコンポーネントの場合、Awake や Start などのライフサイクルメソッドと、 インジェクションが行われるタイミングが前後する可能性があります。 [OnInjected] コールバックは、インジェクションが完了した次のフレームで呼び出されるようになっているため、 初期化順を安定化させる目的で使用できます。
インストーラスクリプトの作成
インストーラは、 Doinject メニューから作成することができます。Project ビューで右クリックし、 Create > Doinject > Component Binding Installer C# Script を選択することで、 インストーラスクリプトが作成されます。

CustomComponentBindingInstallerScript.cs という名前でスクリプトを作成した場合、以下のようなスクリプトが作成されます。
また、動作を確認するため、DIコンテナに登録するオブジェクトと注入先のスクリプトを以下のように作成します。
プレイヤーオブジェクト
注入先スクリプト
Player オブジェクトのインスタンスがInjectTargetScript.Construct() を通じて インジェクトされることがゴールとなります。
では、インストーラーにバインディングを記述していきましょう。 バインディングは、Install メソッド内で行います。
.Bind<Player>() は、Player クラスをコンテナを通じて提供してもらうための宣言です。 .Args("Novice Player") は、Player クラスのコンストラクタにわたす引数となります。 .AsSingleton() は、コンテナを通じて提供される Player オブジェクトがシングルトンであることを示します。
バインド記述は、此のように Fluent Interface を通じて行います。 記述の仕方により、ファクトリとして振る舞ったり、インターフェースを介してインスタンスを提供してもらうようにしたりと柔軟な振る舞いの定義ができます。
これで、コンテクスト内で唯一となる Player オブジェクトが、DIコンテナに登録されました。
最後に、インストーラーをシーンに配置しましょう。

コンポーネントインストーラーは、基本的にシーンのどこに置いてあっても機能します。 また、複数の異なるインストーラーがあっても構いません。 わかりやすさのため、エントリポイントの下に置くなどルールを決めておくのが良いでしょう。
動作確認
先程つくった、InjectTargetScript コンポーネントを、シーンに配置しましょう。

では、シーンを再生してみます。

Player の Name に "Novice Player" という文字列が設定されていることが確認できます。
Player のコンストラクタに Args で指定した引数が渡り(コンストラクタインジェクション)、 さらに、InjectTargetScript の Construct メソッドに Player オブジェクトが渡ったことが確認できました(メソッドインジェクション)。
補足
- シーン全体に配置されたオブジェクトは、すべてシーンコンテクストに包まれます。
シーンコンテクストは、生成時に、自身のコンテクストに属するインストーラーを探し、それらの定義に従ってバインディングを行います。
すべてのインストーラーのバインディングが完了すると、DIContainer は自身が扱うべき型とインスタンス解決方法を知っている状態となります。
その後、シーンコンテクストは、シーン内のすべてのゲームオブジェクトを探索し、IInjectableComponent を実装したコンポーネントを探します。
IInjectableComponent を実装したコンポーネントが見つかったら、そのコンポーネントの [Inject] 属性が指定されたメソッドの引数と型が一致するインスタンスを渡すよう呼び出します。
シーンコンテクストは、シーンのライフサイクルに合わせて生成され、シーンが破棄されると同時に、コンテナが抱えるインスタンスとともに破棄されます。