imog

主にUnityとかの事を書いています

ZenjectからVContainerに移行する際に気をつけること

ニッチすぎる小ネタです。

DIライブラリのリプレースなので基本的にはそんなに手間ではないですが、微妙に思想の違いがあるのでちょっとだけ気をつけようねというお話。

基本的な移行の流れ

  • SceneContextLifetimeScopeに乗り換える
    • Installerのコードを見ながらLifetimeScopeに同様のオブジェクトを登録していく
  • Zenject.InjectVContainer.Inject に乗り換える
    • シーン上のオブジェクトは LifetimeScopeAutoInjectGameObjects に登録していく

DIコンテナとしての役割は同じなので、スクリプトがそのまま差し替わると理想的です。が、全部が全部とはいきません。

ZenjectにあってVContainerにないもの

この辺は、VContainerがそもそもMonoBehaviourへのInjection自体をあまり推奨していない設計思想だからです。ドキュメントに書かれてたりします。

https://vcontainer.hadashikick.jp/ja/resolving/gameobject-injection

ということで、コードに大きく修正を加えないならば上記2点はどうにかシーンから探し出し AutoInjectGameObjects に登録していく必要があります。

ZenjectBindingが使われているか調べる

シーン内をひたすら ZenjectBinding で検索します。Prefabに潜んでいる可能性もあるのでそちらも検索します。がんばる。

ちなみにRiderやReSharper使ってるとクラスからUnityプロジェクト内の参照検索ができるので、ZenjectBindingがアタッチされているPrefabやシーンのGameObjectが洗い出せます。

https://pleiades.io/help/rider/Features_Unity.html#find-usages

シーン内にアタッチされたInject属性のついたコンポーネントを探す

Zenjectはシーン内のInject属性を全検索してInjectionするので追加する分には何も考えなくていいので非常に楽。

その一方で「ヒエラルキー上のどのGameObjectがInjectionの対象なのか」を洗い出したいときに結構手間がかかります。そういう絞り込みができないので・・・。ということで今回は次の方法で調査しました。

  • シーンにLifetimeScopeを置く
  • おもむろにシーン内のSceneContextを削除する
  • 実行したらものすごい数のエラーが出る
    • だいたいInjectionされなくなったことによるnull参照エラー
  • エラーが出たクラスの Zenject.Inject 属性に VContainer.Inject を重ねる
[VContainer.Inject]
[Zenject.Inject]
public void Construct(Foo foo) {}
  • エラーが出たオブジェクトを全部 AutoInjectGameObjects に登録する
  • Zenject.Inject を消す

これを1シーンごとにやっては修正する・・を繰り返しましょう。

所感

インジェクションに限らず、特定のルールに沿うだけで自動で設定してくれるという感じの機能は開発速度を向上させる頼もしい仕組みです。しかし、何が自動化の対象になっているのかが把握、またはロールバックする方法もセットで用意されていないと利用者側はただ把握できないだけになってしまうので、技術選定する際はこの辺気をつけたほうがいいな~と思ったのでした。

追記

SubContainerだったりOptionalInjectionだったりとSignalだったりZenjectにしかない機能はいっぱいあるので、その辺まで含めた場合の乗り換えはコードの見直しからが必要なのでもっと大変です。頑張って・・。

とはいえ、そこまでZenjectに乗っかっているならVContainerに移行する必要はないんじゃないとも思う。