Zenjectことはじめ
単純にコンテナ作って注入して、という使い方をしていたので、Unityらしい使い方を理解しておく
Zenject では、以下のような流れでインジェクションを行っていきます。
1. シーンに、SceneContext というコンポーネントのついたゲームオブジェクトを設置します(これはコンテキストメニューから行います)
2. SceneContext に対して、MonoInstaller というクラスを継承したゲームオブジェクトを指定します。
3. 指定された MonoInstaller は、DiContainer というクラスのインスタンスにバインド情報を登録します。
4. シーンがロードされる際、シーン内に存在するスクリプトの Inject属性がついているメンバ全てにインジェクションを行います。
コンテナのResolveを直に呼び出す処理は基本書かない
まあコンテナの存在は意識したくないしな…
サービスロケータになりそう
どのフレームワークでも基本そうなっている
注入方法
引数で指定
コンストラクタ
メソッド
属性で指定
フィールド
プロパティ
呼ばれる順番は、コンストラクタ->フィールドまたはプロパティ->メソッドの順番
Monobehaviorはコンストラクタがないので、メソッド注入をコンストラクタ替わりに使えばいいと
ただAwakeやStartのコールバックを待つ必要があることを気を付けましょう
ZenjectはDIの影響範囲を指定できる
Project Context
プロジェクト内で有効
ResourcesにContextのアセットを入れておく
Scene Context
シーン内で有効
ヒエラルキーにSceneContextをアタッチしたGameObjectを配置
SceneContextにInstallerを登録
SceneContractを使うと他のシーンまで影響範囲を広げることができる
SceneDecoratorContextを使うと他のシーンから影響を受けることができる
GameObject Context
GameObjectとその子孫で有効
Zenjectで使うInstaller
MonoInstaller
MonoBehaviour派生のInstaller
GameObjectにアタッチした状態で、Contextに登録する
GameObjectの名前がフィールドに表示される
SceneContextをアタッチしたGameObjectにMonoInstallerをアタッチしてもいい
Prefab Installer
Prefab Installerというクラスが存在するのではなく、MonoInstallerをPrefab化したもの
シーンオブジェクトではなくアセットになる
Context上ではMonoInstallerとは別扱いになる
ScriptableObjectInstaller
ScriptableObject派生のInstaller
PrefabInstallerと同様にアセットとなる
ランタイムで値を更新できるのがメリットらしい
変更した値を保存しておく?
DIの誤解について
無理してインターフェース生やさなくてもいいよ
重要なのはDIフレームワークを使うことで「単一責任の原則」に従ったコードが書けることだよ
MonoBehaviourはメソッドインジェクションを推奨
コンストラクタインジェクションと同様に、基底クラスから順に処理される
Installer派生クラスの定義が HogeInstaller : MonoInstaller<HogeInstaller> になっている理由がわかってない
TODO: これについて調べる
Note also that when using the Installer<> base class, we always must pass in ourself as the generic argument to Installer<>. This is necessary so that the Installer<> base class can define the static method BarInstaller.Install. It is also designed this way to support runtime parameters (described below).
別にMonoInstallerはこうしなくてもいい
Installerはこうする必要がある?
Installer<T>について
public static void Install(DiConainer conteainer)メソッドを持ったInstaller派生クラスを定義できる
staticメソッドでバインディングできる
複数のMonoInstallerから同様のバインディングをするときに使う?
Edit -> Zenject -> Validate Current Sceneでバインディングの検証ができる
シーン上のコンポーネントを検索して、そのインスタンスをバインドすることができる
ProjectContextについて
Assets/Resourcesに置いておくと、いずれかのSceneContextの初期化前にProjectContextの初期化が走る
ProjectContextはDontDestroyOnLoadなのでシーン変更時に破棄されない
ProjectContextの初期化が一度実行された後、再度実行されることはない
ProjectContextのコンテナは、すべてのcontextのコンテナの親となる
すべてのシーンから参照されることで意図しない動作につながる可能性があるため、取り扱いには注意が必要
SceneContextで使う例
グローバルなシングルトンを撲滅するためにZenjectを使ってみようという話
Initializableについて
インスタンスが生成されている場合、MonoBehaviour.Start()と同じタイミングでIInitializable.Initialize()が呼ばれる
どこでインスタンスが生成されているのか?
SceneContext then constructs all the non-lazy root objects, which includes any classes that derive from ITickable / IInitializable or IDisposable, as well as those classes that are added with a NonLazy() binding.
IInitializableを実装したクラスはnon-lazyとして扱われる