VContainer v1.6.0 で HelloWorld
とりあえずVContainerのDocのGetting Startedをやって,Hello Worldを表示する所までやってみました.
検証環境
- Unity 2020.3.1f1
- VContainer 1.6.0
- UniRx 7.1.0
VContainer
Extenject の軽量版,必要十分でシンプルな機能を持つUnity用のDIコンテナライブラリです. English ですが Document は十分整備されている上,Extenject より機能が絞られているので, 学習コストは Extenject より少ないと思います.もし Extenject を使ったことがあるなら,すぐにとっかかりやすいでしょう.
Unity用 DI ライブラリの VContainerの webサイトができました。https://t.co/CmCzWTJPaS
— ハダシA (@hadashiA) 2020年12月11日
README ペラ1だったドキュメントをこっちに移行しつつ、
日本語版も準備中らしい!
VContainer と Extenject の相違点
こちらは私がざっと触ってみた感じなので,確実な正解ではないと思われます.(誤っていたら指摘お願いいたします.)
- Extenject は SceneContext ← 分割された複数のInstallerを埋めるということは出来ていたが,現在のVContainerの場合,Installerを作成する工程がなく,Extenjectで分割されたInstallerは1LifetimeScopeに統合してRegisterの記述をする感じ?
VContainerですが、使うときに「Installer」というものをつくる工程を削除 & 文字列をキーにした親参照も削除、型をキーにした参照に変えるという めっちゃ破壊的変更がはいる予定です。既に使ってくれている方ごめんhttps://t.co/tsbPu0AwDI
— ハダシA (@hadashiA) 2020年7月12日
このツイートを見るに過去は Installer を作成する工程はあった模様.
Extenject は Multi-Parent は簡単に出来るが,VContainer の場合は出来なさそう? Inspector上では Parent は1つしか出来なかった.コードの方で Child Scope 生成あたりで無理くり出来るか否かまだ試してない. というよりここら辺は Extenject と VContainer で思想が異なりそう. Extenject の Multi-Parent は微妙に Unity の Multi-Scene あたりで重宝したので,VContainer でも上手い具合に試す必要がある.
UniRx, UniTask との統合が一応考慮されている (非同期想定)
VContainer × UniRx でハロワ
こちらのGetting Startedをやってみました. そのままだと味気ないので一応軽くUniRxを交えたり,Interface作ったりして試してみた.
using System; using UnityEngine; using UnityEngine.UI; using UniRx; namespace Denik.VContainerPractice.HelloWorld { /// <summary> /// View クラス /// </summary> internal class HelloWorldView : MonoBehaviour, ITrigger { [SerializeField] private Button helloButton; public IObservable<Unit> OnTriggerAsObservable() => _onTriggerSubject; private Subject<Unit> _onTriggerSubject = new Subject<Unit>(); private void Awake() { helloButton.OnClickAsObservable() .Subscribe(_ => _onTriggerSubject.OnNext(Unit.Default)); } } internal interface ITrigger { IObservable<Unit> OnTriggerAsObservable(); } }
using UnityEngine; using UniRx; using VContainer; using VContainer.Unity; namespace Denik.VContainerPractice.HelloWorld { /// <summary> /// LifetimeScope クラス /// </summary> internal class HelloWorldLifetimeScope : LifetimeScope { [SerializeField] private HelloWorldView helloWorldView; protected override void Configure(IContainerBuilder builder) { builder.Register<HelloWorldService>(Lifetime.Singleton); builder.RegisterEntryPoint<GamePresenter>(Lifetime.Singleton); builder.RegisterComponent(helloWorldView).AsImplementedInterfaces(); } } /// <summary> /// Service クラス /// </summary> internal class HelloWorldService { public void Hello() { Debug.Log("Hello world"); } } /// <summary> /// Presenter クラス /// </summary> internal class GamePresenter : IStartable { private readonly HelloWorldService _helloWorldService; private readonly ITrigger _helloWorldView; [Inject] public GamePresenter(HelloWorldService helloWorldService, ITrigger helloWorldView) { _helloWorldService = helloWorldService; _helloWorldView = helloWorldView; } public void Start() { _helloWorldView.OnTriggerAsObservable() .Subscribe(_ => _helloWorldService.Hello()); } } }
ハロワ!やったね.
終わりに
Extenjectは今まで最低限の機能しか使っていなかったマンなので,VContainerでいいかなあというムーブになりそう. まだVContainer触れたばかりなので,Extenjectにはこんなの簡単に出来たのに~とかこれから他にも発生するかもしれない. もう少しVContainer勉強してみます.
余談
弊社では UniRx,UniTask,Extenject のことは三種の神器って呼んでいるんですが,他社もそうなのだろうか….
ちなみにこれからは Extenject から VContainer に移行し,呼び方が新・三種の神器になりそうな感じです.