【Unity】【Zenject】Containerでバインドする際の設定まとめ

ZenjectでInstallerなどを使ってバインド処理を書く際の設定をまとめます。

Unity2018.2
Zenject7.3.1

設定一覧

まず設定の一覧です。
これらについて説明していきます。

Container.Bind<IExample>()
    .To<Example>()
    .WithId("exampleId")
    .FromNew()
    .AsTransient()
    .WithArguments("example")
    .OnInstantiated((context, obj) => {})
    .When()
    .NonLazy()
    .IfNotBound();

Bind()とTo()

まずBind()は依存性を注入する対象の型を指定するためのメソッドです。
このクラスあるいはインタフェースが定義され、Injectアトリビュートがついているフィールドに注入されます。

これに対してTo()は実際に注入する型を指定するメソッドです。
Bind()でインタフェースを指定してTo()でそれを実装するクラスの型を指定する、といった使い方をします。
Bind()に指定した型と同じいいのであればTo()は書かなくてOKです。

Container
    .Bind<IExample>() // この型で定義されたフィールドに
    .To<Example>() // この型のインスタンスを注入する

WithId()

いま、同じインタフェースIExampleのフィールドが二つ定義されているとします。
このうち片方にはこれを実装したExample1というクラスを、他方にはExample2というクラスを注入したいとします。
Bind()では注入対象を型でしか判定できないため、このような場合にはWithId()を使います。

使い方としてはまず注入対象のフィールドにInjectアトリビュートをID付きで定義します。

[Inject(Id = "exampleId")] // ID付きで定義する
private Example _example;

private void Update()
{
    Debug.Log(_example);
}

あとはWithId()の引数にこれを指定するだけです。

Container
    .Bind<IExample>()
    .To<Example>()
    .WithId("exampleId")

ちなみにIDは文字列でもいいのですがEnumが推奨されているようです。

public enum ExampleEnum{
    First,
    Second
}

[Inject(Id = ExampleEnum.First)]
private Example _example;

FromNew()

これは「インスタンスをどのように生成するか」を定義しています。
別記事で詳しく解説していますので下記を参照してください。

light11.hatenadiary.com

AsTransient()

これは「注入が2回以上行われるときにインスタンスを再利用するかどうか」を定義します。
次の三つのメソッドが存在します。

名前 説明
AsTransient() インスタンスを再利用しない
AsCached() インスタンスを再利用する
AsSingle() インスタンスを再利用する
二回以上Bind()されると例外になる

AsCached()AsSingle()がわかりづらいので例を挙げます。
例えばいまインタフェースIExampleとそれを実装するExampleがあり、
これらをIExampleExampleを注入するためのフィールドがそれぞれ定義されているとします。

これらに対してまずAsCached()を使って依存性注入してみます。

// これはエラーにならない
// Example型とIExample型のフィールドにはそれぞれ別のExample型のインスタンスが注入される
Container.Bind<Example>().AsCached();
Container.Bind<IExample>().To<Example>().AsCached();

これに対してAsSingle()を使って注入すると下記のようになります。

// これは例外が発生する
// Example型のインスタンスが二つ存在してはいけないため
Container.Bind<Example>().AsSingle();
Container.Bind<IExample>().To<Example>().AsSingle();

つまり、AsSingle()はシングルトンにしたいオブジェクトに定義するものだといえます。

WithArgument()

注入するオブジェクトを生成する際のコンストラクタに渡す引数を指定できます。

Container
    .Bind<Example>()
    .AsTransient()
    .WithArguments("example");

OnInstantiated()

注入するオブジェクトが生成されたときのコールバックを指定できます。

Container
    .Bind<Example>()
    .AsTransient()
    .OnInstantiated((context, obj) => Debug.Log("instantiated."));

When()

注入対象を絞れます。
例えば注入対象のフィールドを持つコンポーネントの型に応じて注入するインスタンスを分ける場合は次のようにします。

Container
    .Bind<IExample>()
    .To<Example1>()
    .AsSingle()
    .When(context => context.ObjectType == typeof(Target1));

Container
    .Bind<IExample>()
    .To<Example2>()
    .AsSingle()
    .When(context => context.ObjectType == typeof(Target2));

ちなみに上記のような用途の場合はWhenInjectedInto()を使って次のようにも書けます。

Container
    .Bind<Example>()
    .AsSingle()
    .WhenInjectedInto<Target>();

NonLazy()

通常は実際に注入されるときに始めて注入するインスタンスが作られますが、
NonLazy()を指定すると最初に作られます。

IfNotBound()

既に同じ型のインスタンスが一つでもバインドされていたらバインド処理をスキップします。

関連

light11.hatenadiary.com

light11.hatenadiary.com

参考

github.com