MRが楽しい

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

VContainerのHelloWorldを試す その6(親子関係のあるLifetimeScopeの依存解決の順番)

本日は VContainer の小ネタ枠です。
親子関係のある LifetimeScope の依存解決の順番を確認して記事に残します。

前回記事

以下の前回記事のプロジェクトを組み合わせて利用します。
bluebirdofoz.hatenablog.com
bluebirdofoz.hatenablog.com

親子関係のあるLifetimeScopeの依存解決の順番

結論から述べると、親子関係のある LifetimeScope の依存解決は子の LifetimeScope から親に向かって探索されます。
vcontainer.hadashikick.jp

動作確認

実際に動作を確認してみました。
以下のデバッグ用のスクリプトを作成してそれぞれ projectRoot、EnqueueParent、自身の LifetimeScope いずれから IHelloWorldService のインスタンスを解決するか確認しました。
・RootParentLifetimeScope.cs(projectRootに設定したLifetimeScope)

using VContainer;
using VContainer.Unity;

namespace EnqueueParentSample2
{
    public class RootParentLifetimeScope : LifetimeScope
    {
        protected override void Configure(IContainerBuilder builder)
        {
            // DebugHelloWorldServiceをインタフェースとしてDIコンテナに登録する
            builder.RegisterInstance(new DebugHelloWorldService("RootParent",200)).As<IHelloWorldService>();
        }
    }
}

・EnqueueParentLifetimeScope.cs(EnqueueParentで親に指定するLifetimeScope)

using VContainer;
using VContainer.Unity;

namespace EnqueueParentSample2
{
    public class EnqueueParentLifetimeScope : LifetimeScope
    {
        protected override void Configure(IContainerBuilder builder)
        {
            // DebugHelloWorldServiceをインタフェースとしてDIコンテナに登録する
            builder.RegisterInstance(new DebugHelloWorldService("EnqueueParent",100)).As<IHelloWorldService>();
        }
    }
}

・GameLifetimeScope.cs(解決を行う自身のLifetimeScope)

using UnityEngine;
using VContainer;
using VContainer.Unity;

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

        protected override void Configure(IContainerBuilder builder)
        {
            // HelloWorldServiceをインタフェースとしてDIコンテナに登録する
            builder.Register<HelloWorldService>(Lifetime.Singleton).As<IHelloWorldService>();
            // GamePresenterをVContainerのEntryPointに登録する
            builder.RegisterEntryPoint<GamePresenter>();
            // HelloScreenコンポーネントをDIコンテナに登録する
            builder.RegisterComponent<HelloScreen>(helloScreen);
        }
    }
}

・IHelloWorldService.cs

namespace EnqueueParentSample2
{
    public interface IHelloWorldService
    {
        void Hello();
    }
}

・HelloWorldService.cs

namespace EnqueueParentSample2
{
    public class HelloWorldService : IHelloWorldService
    {
        private int count = 0;

        public void Hello()
        {
            count++;
            UnityEngine.Debug.Log($"Hello world : {count}");
        }
    }
}

・DebugHelloWorldService.cs

namespace EnqueueParentSample2
{
    public class DebugHelloWorldService : IHelloWorldService
    {
        private string name = "";
        private int count = 0;

        public DebugHelloWorldService(string name, int count)
        {
            this.name = name;
            this.count = count;
        }

        public void Hello()
        {
            count++;
            UnityEngine.Debug.Log($"Hello world : {count} by {name}");
        }
    }
}

結果は以下の通り、自身の LifetimeScope で生成した IHelloWorldService のインスタンスが参照されました。

次に以下の通り、自身の LifetimeScope から IHelloWorldService のインスタンス解決を削除して試しました。
・GameLifetimeScope.cs(解決を行う自身のLifetimeScope)

using UnityEngine;
using VContainer;
using VContainer.Unity;

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

        protected override void Configure(IContainerBuilder builder)
        {
            // GamePresenterをVContainerのEntryPointに登録する
            builder.RegisterEntryPoint<GamePresenter>();
            // HelloScreenコンポーネントをDIコンテナに登録する
            builder.RegisterComponent<HelloScreen>(helloScreen);
        }
    }
}

この場合は以下の通り、EnqueueParent で設定した LifetimeScope が参照されました。