【Unity】【Zenject】いろんなものを依存性注入する

以前、Zenjectを簡単に使って概要を理解するための記事を書きました。

light11.hatenadiary.com

Zenjectは非MonoBehaviourのインスタンスからテクスチャなどのAssetまでいろんなものを注入できます。
この記事ではいろんなものを依存性注入する方法をまとめます。

Unity2018.2.0
Zenject 7.3.1

準備

準備として、SceneContextにMonoInstallerを持たせておきます。
このあたりのやり方は下記の記事を参照してください。

light11.hatenadiary.com

非MonoBehaviourを注入

まずは非MonoBehaviourのクラスのインスタンスを注入してみます。
インスタンスの生成方法により次の三つの方法があります。

メソッド名 説明
FromNew() newによりインスタンスを生成する(デフォルト)
FromInstance() すでに存在するインスタンスを使う
FromMethod() インスタンス生成用のメソッドを使って生成

FromNew()はこんな感じで使います。
何も指定しない場合はFromNewになります。

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromNew() // new Example() によりインスタンスを生成する
        .AsTransient();
}

FromInstance()はこんな感じです。

public override void InstallBindings()
{
    var instancde = new Example();

    Container
        .Bind<IExample>()
        .To<Example>()
        .FromInstance(instancde) // すでにあるインスタンスを使う
        .AsTransient();
}

FromMethod()はこんな感じです。

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromMethod(CreateExample) // メソッドを使って生成する
        .AsTransient();
}

private Example CreateExample()
{
    return new Example();
}

MonoBehaviourを注入

GameObjectにアタッチされているMonoBehaviourを注入する方法は次の通りです。
ただしPrefabをインスタンス化する場合は別の方法があるので次節で説明します。

メソッド名 説明
FromNewComponentOnNewGameObject() GameObjectを新規生成してコンポーネントをアタッチする
FromComponentOn()
FromNewComponentOn()
引数のGameObjectにアタッチされたコンポーネントを使う
FromComponentOn()は予めアタッチされたコンポーネントを使う(無ければ例外)
FromNewComponentOn()コンポーネントを新規でアタッチ
(予めアタッチされていてももう一つアタッチする)
FromComponentSibling()
FromNewComponentSibling()
注入対象のGameObjectにアタッチされたコンポーネントを使う
FromComponentSibling()は予めアタッチされたコンポーネントを使う(無ければ例外)
FromNewComponentSibling()コンポーネントを新規でアタッチ
(予めアタッチされていたらそれを使う)
FromComponentInChildren()
FromComponentInParents()
FromComponentInHierarchy()
FromComponentOnRoot()
それぞれ 子/親/ヒエラルキー/Contextのルート に
アタッチされているコンポーネントを使う(無ければ例外)

FromNewComponentOnNewGameObject()はこんな感じに使います。
注入処理が行われるときにGameObjectが新規作成されます。

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromNewComponentOnNewGameObject() // GameObjectを新規生成してコンポーネントをアタッチする
        .AsTransient();
}

FromComponentOn()FromNewComponentOn()はこんな感じでアタッチ対象のGameObjectを渡します。

[SerializeField]
private GameObject _gameObject;

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromComponentOn(_gameObject)
        .AsTransient();
}

FromComponentSibling()FromNewComponentSiblingはこんな感じで使います。
FromNewComponent()はすでにアタッチされていても二つ目のコンポーネントをアタッチするのに対して
FromNewComponentSibling()はすでにアタッチされていたらそれを使うようなので注意が必要そうです。

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromComponentSibling()
        .AsTransient();
}

FromComponentInChildren() / FromComponentInParents() / FromComponentInHierarchy() / FromComponentOnRoot() はこんな感じに使います。

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromComponentInChildren()
        .AsTransient();
}

Prefabをインスタンス化してMonoBehaviourを注入

PrefabにアタッチされたMonoBehaviourを注入する方法は次の通りです。

メソッド名 説明
FromComponentInNewPrefab()
FromNewComponentOnNewPrefab()
引数のPrefabをインスタンス化してアタッチされたコンポーネントを注入する
FromNewComponentOnNewPrefab()の場合はPrefabのインスタンスに新しくコンポーネントをアタッチする
FromComponentInNewPrefabResource()
FromNewComponentOnNewPrefabResource()
FromComponentInNewPrefab()FromNewComponentOnNewPrefab()
基本的に同様の挙動だが、PrefabをResourcesから読み込む

FromComponentInNewPrefab()FromNewComponentOnNewPrefab()は次のようにして使います。
引数にはPrefabを与えます。

[SerializeField]
private Object _prefab;

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromComponentInNewPrefab(_prefab)
        .AsTransient();
}

FromComponentInNewPrefabResource()FromNewComponentOnNewPrefabResource()は次のように使います。
引数にはResourcesのパスを与えます。

[SerializeField]
private string _prefabResourcePath;

public override void InstallBindings()
{
    Container
        .Bind<IExample>()
        .To<Example>()
        .FromComponentInNewPrefabResource(_prefabResourcePath)
        .AsTransient();
}

いろんな型のAssetをResourcesから読み込んで注入

コンポーネントではなくTextureなどのAssetをResources.Load()で読み込んで 注入するにはFromResource()を使います。

[SerializeField]
private string _resourcePath;

public override void InstallBindings()
{
    Container
        .Bind<Texture2D>()
        .FromResource(_resourcePath)
        .AsTransient();
}

ただしこれでは全てのTexture2D型に同じテクスチャが注入されてしまうので、
実際にはWithId()を使ったりするようです。

Container
    .Bind<Texture>()
    .WithId("ExampleTex")
    .FromResource(_resourcePath)
    .AsTransient();

シーン上のMonoBehaviourをInstallerを書かずに手軽に注入

Zenject Bindingというコンポーネントを使うと、シーンに置かれたGameObjectの
MonoBehaviourを、Installerを書くことなく注入できます。

使い方は次の通りです。

  1. 注入したいコンポーネントをアタッチしたGameObjectを作る
  2. 1.にZenject Bindingをアタッチする
  3. 2.のComponentsに1.のコンポーネントを代入する

こんな感じになります。

f:id:halya_11:20190102165331p:plain

後は再生すれば依存性が解決されます。

まとめ

Zenjectにおけるいろんな依存性注入の方法を紹介しました。
依存性注入の方法はまだまだあるので、もっと詳しく知りたい方はドキュメントを参照してください。

github.com

関連

light11.hatenadiary.com