VContainerという新しい選択肢　〜UnityのDIライブラリ〜

[PONOS Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ponos) の11日目の記事です。
昨日は[@block](https://qiita.com/block)さんの[Unity 2020から自動実装プロパティのバッキングフィールドにSerializeField属性をつけるとプロパティ名が表示される](https://qiita.com/block/items/05086f31939ee115aa74)にするでした。

#VContainerって何？
VContainerとは<a href="https://github.com/hadashiA">hadashiA</a>さんが作成されたUnity用の軽量DIライブラリとなっています。
現在主流となっているZenjectより軽量で高速となっています。
ではなぜ今VContainerを記事にしようと思ったかといいますと、ver1.0.0がリリースされたからです（現時点では1.3.0がリリースされています）
#インストール
**環境**
Unity:2019.4.1f1
VContainer:1.3.0

[こちら](https://github.com/hadashiA/VContainer#installation)のInstallationよりUPMかunitypackageのどちらかの方法でインストールします。今回私はUPMを使用しました。
UPMの使い方については詳しくは記載しませんので[こちら](https://docs.unity3d.com/ja/2019.4/Manual/upm-ui-giturl.html)を参考にしてください。

#使い方
今回は導入から簡単なサンプルを紹介していこうと思っていますので一番初歩として「Hello World」をテキストに表示するサンプルにしようと思います。

まず**LifetimeScope**を生成します。方法はProjectタブにて右クリックで**Create→C# Script**にてHogeHogeLifetimeScopeと入力するとLifetimeScopeを継承したファイルが作成されます。今回は**SampleLifetimeScope**という名前で作成しました。
次にHierarchyにて空のオブジェクトを作成し、先ほど作成したSampleLifetimeScopeをアタッチします。

これから実際の処理を記述していきます。

```SampleLifetimeScope.cs
using VContainer;
using VContainer.Unity;
using UnityEngine;

namespace VContainerSample
{
    public class SampleLifetimeScope : LifetimeScope
    {
        [SerializeField] SampleView view;

        protected override void Configure(IContainerBuilder builder)
        {
            builder.Register<ISampleText, SampleText>(Lifetime.Scoped);
            builder.RegisterComponent(view);
        }
    }
}
```


```SampleText.cs
namespace VContainerSample
{
    public interface ISampleText
    {
        string Text { get; }
    }

    public class SampleText : ISampleText
    {
        public string Text => $"Hello World";
    }
}
```


```SampleView.cs
using UnityEngine;
using UnityEngine.UI;
using VContainer;

namespace VContainerSample
{
    public class SampleView : MonoBehaviour
    {
        [SerializeField] Text text;

        [Inject]
        public void Construct(ISampleText sampleText)
        {
            text.text = sampleText.Text;
        }
    }
}
```

これでSampleView.csのTextに「Hello World」が表示されるようになります。

![スクリーンショット 2020-12-09 23.08.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/914167/e5da3410-7e71-8412-fc50-bff29bb060d8.png)


#Zenjectとの比較

``` SampleMonoInstaller.cs
using UnityEngine;
using Zenject;

namespace ZenjectSample
{
    public class SampleMonoInstaller : MonoInstaller
    {
        [SerializeField] GameObject view;

        public override void InstallBindings()
        {
            Container.Bind<ISampleText>().To<SampleText>().AsCached();
            Container.InjectGameObjectForComponent<SampleView>(view);
        }
    }
}
```

``` SampleView.cs
using UnityEngine;
using UnityEngine.UI;
using Zenject;

namespace ZenjectSample
{
    public class SampleView : MonoBehaviour
    {
        [SerializeField] Text text;

        [Inject]
        public void Construct(ISampleText sampleText)
        {
            text.text = sampleText.Text;
        }
    }
}
```
Zenjectで同様の処理を書いたらこのようになります。
VContainerとの違いはLifetimeScopeとMonoInstallerになると思います。
Zenjectにおける`Bind`の役割はVContainerの場合は`Configure`にて`IContainerBuilder`へRegistになっており、クラスからインターフェースへの変換は`builder.Register<ISampleText, SampleText>(Lifetime.Scoped)`で行っています。これはZenjectの`Container.Bind<ISampleText>().To<SampleText>().AsCached()`と同じような処理となっています。
このように簡単な部分だけを見るとZenjectからVContainerへの移行はとっつきやすいと考えられます。

#まとめ
新しく登場したVContainerについてとても簡単なプログラムの作り方をまとめました。
これから新しく生まれるプロジェクトでは採用されるようになっていくとどんどん情報も出てきて賑わってくれると思っています。
軽量で高速という部分については[こちら](https://hadashia.hatenablog.com/entry/2020/08/17/024922)にて記載されておりますので、興味のある方は参考にしてみてください。
上記のサンプルだけでも実行してみたらその速度の違いに私は驚きました。
次はもう少しゲームよりなサンプルを作って、実際にどう作っていけば良いかを解説していければと思っています。
ぜひ皆さんも触ってみてください。

[VContainerを組み込んだゲームサンプル](https://qiita.com/kenta-san/items/21bc7e0ebe1ded6e2ac7)こちらも併せてご覧になってください。


明日は[@honeniq](https://qiita.com/honeniq)の記事です。ぜひ見てください！