ニッチすぎる小ネタです。
DIライブラリのリプレースなので基本的にはそんなに手間ではないですが、微妙に思想の違いがあるのでちょっとだけ気をつけようねというお話。
基本的な移行の流れ
SceneContext
→LifetimeScope
に乗り換える- Installerのコードを見ながらLifetimeScopeに同様のオブジェクトを登録していく
Zenject.Inject
→VContainer.Inject
に乗り換える- シーン上のオブジェクトは
LifetimeScope
のAutoInjectGameObjects
に登録していく
- シーン上のオブジェクトは
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に移行する必要はないんじゃないとも思う。