読者です 読者をやめる 読者になる 読者になる

【Unity】ZenjectのAsSingle(),AsCached(),AsTransient()の違い

 

 

調べてみた。

 

超適当にテストコード書いて挙動を確かめた

メソッドの名前が意味不明なのは許してほしい

 

gist.github.com

 

挙動を理解しないとヤバい事故生みそうだなこれという結果になった

結果的にはAsSingle()でInjectされてる参照がUnbindで破棄されてなくて、Inject済みの参照をもう一回Bindし直してた

あとGCで回収されてなかった

 

そもそも

As〜ってなんぞやというと

BindするクラスやインスタンスのBind方法の定義である

 

https://github.com/modesttree/Zenject#binding

 

AsSingle(),AsCached()はキャッシュするのね〜

AsTransientはキャッシュ作らないのね〜くらいの認識だと

しぬ(しんだ)

 

AsTransient()

クラスをBindする際に複数インスタンスの生成を許容する

クラスがContainerにBindされている際、参照情報が一つであればResolveで解決出来る

 

しかし、Resolveは単一のインスタンスに対してのみ参照を解決するため

AsTransientでBindを複数回行っていた場合、multiple instanceエラーを吐く

 

gist.github.com

 

AsTransientでのBindには必ず.WithId()を使用してIdentiferを定義するか

ResolveAllを使用した参照解決を図るようにした方が良い

 

また、As〜などの定義をしなかった場合はデフォルトでAsTransientになる

Factoryなどを使用したインスタンス生成もAsTransientになるため、Instantiateで複数生成したクラスに対してResolveするとエラー吐く、気をつけよう

(まあInstantiateした時点でResolveすることなんてほとんどないんだけど)

 

AsCached()

Bindされているクラスがすでにインスタンス化されている場合、同じインスタンスを使い回すようにする

また、UnbindするとCacheされていたインスタンスは全て参照を破棄される

 

同じインスタンスは使いまわしたいが、Unbindで破棄したい時はこれを使用する

クセがなく、取り回しがしやすいので動的Bindをする際は非常におすすめしたい

 

AsSingle()

クラスをBindする際にSingletonとして定義する

クラスがContainerにBindされている際は

「そのContainer内で唯一存在するクラス」となることが保障される

 

Bindされている際は、Cachedと同じ挙動をする

 

しかし、Unbindを呼んだ際に

Bindした自身の参照を他のクラスにInjectしなくなるが、生成したインスタンス自体は破棄されずキャッシュされたまま

のため、Unbindを呼び、その後もう一度同じクラスをBindしても

new()などが走らず、キャッシュされていた参照をもう一度Bindして使い回す

 

gist.github.com

(HashCodeでやっているが、他にもResolveで返ってきた値の中身を書き換えたところどちらも書き換わった)

 

AsSingle()は必ず一つ、かつ一度しか生成されないオブジェクトに対してのみ使用しよう

 

 

まとめ

readmeには、「AsSingle()をほとんどの場面で使いたいと思うでしょうが〜」とか書いてあるけど

基本AsCached()でいいわ。

 

AsSingle()で動的Bindすると初期化走らせられなくてビビった結果、動作を知れたのでまあよかったと思う。

 

あと、ZenjectのUnitTestマジで神以外の何物でもないのでバンバン使っていきたい