【Unity】VContainerのLifetimeScopeのParent機能使って見た # 1

# はじめに
この記事は[Hamster Output Advent Calendar 2024](https://qiita.com/advent-calendar/2024/game_hamster)の11日目の記事です！

今回はVContainerの**Parent機能**を使ったことや...制作中に悩んだことなどをこの記事に書きたいと思います！詳細な内容は、詳しい解説などは本記事を見るよりも、参考にしたリンクの記事を見ることをオススメします。

# 参考にしたリンク

https://qiita.com/sakano/items/fbb63867750ec6ac6d0f

# この記事を作ったきっかけ
LifetimeScopeを作って配置している時に、ふとあることを考えました。他のLifetimeScopeに登録されている型とかインスタンスを取得したい時ってどうするんだろう...と考えました。

# 試してみる
試しに、LifetimeScopeを2つ作り片方に型を登録、もう片方に型を利用するインスタンスを登録しました。その後にAuto Inject Game Objectsに入れて実験をしました。ソースコードが4つあって長ったるいですが、大した内容は書いていません。

```C#:型として登録したクラス
using UnityEngine;

public class Test
{
    public void Call()
    {
        Debug.Log("Test !");
    }
}
```

```C#:型を登録するLifetimeScope
using VContainer;
using VContainer.Unity;

public class ParentLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<Test>(Lifetime.Singleton);
    }
}
```

```C#:型を利用するインスタンス
using UnityEngine;
using VContainer;

public class TestMonoBehaviour : MonoBehaviour
{
    [Inject]
    private Test _test;

    void Start()
    {
        _test.Call();
    }
}
```

```C#: インスタンスを登録するLifetimeScope
using VContainer;
using VContainer.Unity;

public class ChildLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.RegisterComponentInHierarchy<TestMonoBehaviour>();
    }
}
```

GameObjectにLifetimeScopeとMonoBehaviourをアタッチして、ParentのAuto Inject Game ObjectsにTestMonoBehaviourを入れました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/aa546b7a-bd49-7e6e-8a58-292b447e86e7.png)

そして実行すると、このような結果になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/aa466a1b-f762-2ed1-2b0b-f7e2979fdf01.png)
結果としては、Parentは問題なく依存関係を解決出来たけど、Childの方ではTestという型は登録されていないというエラーになっています。

正直、ChildのLifetimeScopeでの登録を止めればいいだけの話にはなりますが...

# Parent機能を利用して解決
やること自体はとても簡単です。ChildLifetimeScopeのParentという項目をクリックして、ParentLifetimeScopeを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/8066dfec-596b-9e96-7587-135067133497.png)

実行すると、エラーがなくメソッドが実行されていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/ccb536ca-20dc-c8cb-c2ed-4230322cfb20.png)

Parentの親設定に関して、子は同じ親を指定することができます。この時に子が親を指定している状態で、親が他のLifetimeScopeを親にしているとエラーが出ます。また、親は子の内容を利用することはできません。

そして、このParent機能の面白いところは親から子、さらにその子に型とインスタンスを利用させることができます。

すっごい雑な図になるんですけど、図の状態だと親は指定されているだけで、何も利用できない。子Aは親と自身が登録した型やインスタンスを利用できる。そして、その下の階層の子B、Cは親と子Aの型やインスタンスが利用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/5a8b3d9a-6229-c7b1-00b5-d31fd18c4ebf.png)

さっきのインスペクタの内容をこのように変更します。

・親
変更なし
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/6bfd8be3-ac31-0e85-fcdf-0f0b9a595084.png)

・子1
変更なし
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/2f0bba71-23c4-8eed-04b6-496706a09297.png)

・子2 new
子1を親にして、親に登録してある型と、子が登録したインスタンスを利用するクラスを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/c6083ccc-516d-c914-89c4-29362a337aca.png)

```C#
public class ChildTest : IStartable
{
    private readonly Test _test;
    private readonly TestMonoBehaviour _testMonoBehaviour;

    public ChildTest(Test test, TestMonoBehaviour testMonoBehaviour)
    {
        _test = test;
        _testMonoBehaviour = testMonoBehaviour;
    }

    public void Start()
    {
        _test.Call();

        // こそっとLogを出す処理を追加しました
        _testMonoBehaviour.Call();
    }
}
```

実行結果としてはこうなります！子2で、親と子1の型、インスタンスを利用できています。おぉ～便利だ～～
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/7f73ded7-ee08-aab0-10ae-7956df3d49eb.png)

# まとめ
LifetimeScopeで親子関係を作ることができて、親の型やインスタンスを利用することができる。

親→子1→子2という親子関係を作ると、子2では親と子1の型やインスタンスを利用することができる。

そして、この親子関係を利用する場合Lifetime辺りが少し変わってくるらしいです。その部分は明日に続く！