MRが楽しい

MRやVRについて学習したことを書き残す

VContainerのHelloWorldを試す その9(Resolveを使って登録されたインスタンスを参照する)

本日は VContainer の小ネタ枠です。
VContainerでResolveを使って登録されたインスタンスを参照する方法を記事に残します。

サンプルシーン

子となる LifetimeScope からResolveを使って親の LifetimeScope で登録されたインスタンスを参照するサンプルを作成します。

以下の記事のサンプルプロジェクトを基に一部のスクリプトを変更して動作を確認します。
bluebirdofoz.hatenablog.com

プロジェクトルートのLifetimeScopeを参照する

以下の通り、親となるプロジェクトルートのLifetimeScopeでシーンの情報を保持するSceneProfileを登録します。
・RootParentLifetimeScope.cs

using VContainer;
using VContainer.Unity;

namespace ResolverTestSample
{
    public class RootParentLifetimeScope : LifetimeScope
    {
        [SerializeField]
        private SceneType selectSceneType;
        
        protected override void Configure(IContainerBuilder builder)
        {
            var sceneProfile = new SceneProfile{ CurrentSceneType = selectSceneType };
            
            // SceneProfileをDIコンテナに登録する
            builder.RegisterInstance(sceneProfile);
        }
    }
    
    public enum SceneType
    {
        Morning,
        Night,
    }
    
    public class SceneProfile
    {
        public SceneType CurrentSceneType { get; set; }
    }
}

子となる LifetimeScope からは以下の記法で指定クラスに登録されたインスタンスを参照できます。

Parent.Container.Resolve<SceneProfile>();

子となる LifetimeScope を以下の通り変更しました。
SceneProfileの設定に応じて登録するクラスを切り替えます。
・GameLifetimeScope.cs

using System;
using UnityEngine;
using VContainer;
using VContainer.Unity;

namespace ResolverTestSample
{
    public class GameLifetimeScope : LifetimeScope
    {
        [SerializeField]
        private HelloScreen helloScreen;

        protected override void Configure(IContainerBuilder builder)
        {
            // SceneProfileをDIコンテナから取得する
            var sceneProfile = Parent.Container.Resolve<SceneProfile>();
            
            // SceneProfileのCurrentSceneTypeによって、IHelloWorldServiceの実装を切り替える
            switch (sceneProfile.CurrentSceneType)
            {
                case SceneType.Morning:
                    builder.Register<IHelloWorldService, GoodMorningService>(Lifetime.Singleton);
                    break;
                case SceneType.Night:
                    builder.Register<IHelloWorldService, GoodNightService>(Lifetime.Singleton);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            
            // GamePresenterをVContainerのEntryPointに登録する
            builder.RegisterEntryPoint<GamePresenter>();
            // HelloScreenコンポーネントをDIコンテナに登録する
            builder.RegisterComponent<HelloScreen>(helloScreen);
        }
    }
}

SceneProfileの設定に応じてログ出力の動作を切り替えることができました。

ルートプロジェクトで登録されているインスタンスはシーン間で保持されるため、前シーンで行った設定に応じて次シーンのLifetimeScopeの登録を切り替えたい場合などに便利です。