Zenject、雰囲気で使うと爆死しそうな気配がするので、調べてわかったことをちょこちょこ書いていく。最終的にはスライドとかにまとめるかも
前提のAクラスとBクラス
public class TestA
{
public TestA()
{
Debug.Log("TestA");
}
}
public class TestB
{
[Inject]
private TestA a;
public TestB()
{
Debug.Log("TestB");
}
}
Logになんと出る?
[TestFixture]
public class ZenjectInstallUnitTest : ZenjectUnitTestFixture
{
[Test]
public void InstallTest()
{
Container.Bind<TestA>().FromNew().AsSingle();
Container.Bind<TestB>().FromNew().AsSingle();
}
}
答え なにも出ない
依存するインスタンスが存在しないため、バインドされたオブジェクトは生成されない
[Test]
public void InstallTest()
{
Container.Bind<TestA>().FromNew().AsSingle();
Container.Bind<TestB>().FromNew().AsSingle();
Container.Resolve<TestB>();
}
答え
TestB
TestA
- TestBがResolveされるので、そのタイミングで生成
- 依存するTestAがその後生成
Resolveはバインドしたオブジェクトを生成する
public class TestB
{
[Inject]
private TestA a;
public TestB()
{
Debug.Log("TestB");
Debug.Log(a);
}
}
TestB
null
TestA
コンストラクタを通るときはまだInjectされてない!!!
public class TestB
{
[Inject]
private TestA a;
public TestB()
{
Debug.Log("TestB");
}
[Inject]
private void Initialize()
{
Debug.Log(a + " in Initialize");
}
}
TestB
TestA
TestA in Initialize
Inject の実行順は メンバ変数、メソッドの順番
public class TestA
{
[Inject]
private TestC c;
public TestA() { Debug.Log("TestA"); }
}
public class TestB
{
[Inject]
private TestA a;
public TestB() { Debug.Log("TestB"); }
[Inject]
private void Initialize() => Debug.Log(a + " in Initialize");
}
public class TestC
{
[Inject]
private TestB b;
public TestC() { Debug.Log("TestC"); }
}
Logはどうなる?
[Test]
public void InstallTest()
{
Container.Bind<TestA>().FromNew().AsSingle();
Container.Bind<TestB>().FromNew().AsSingle();
Container.Bind<TestC>().FromNew().AsSingle();
Container.Resolve<TestB>();
}
TestB
TestA
TestC
TestA in Initialize
Bを起点に依存するオブジェクトAが生成される。
Aを生成後に依存するCが生成される。
Cを生成後、メソッドインジェクションが行われる
Zenjectは、依存する全てのメンバ変数を注入してからメソッドインジェクションを行う!
ということで、コンストラクタではInjectするメンバ変数に依存してはいけない
[Test]
public void InstallTest()
{
Container.Bind<TestA>().FromNew().AsSingle();
Container.Bind<TestC>().FromNew().AsSingle();
TestB b = new TestB();
Container.Inject(b);
}
TestB
TestA
TestC
まさかのメソッドインジェクションしてくれない。 インスタンス持ってるから自分で呼べということか。
README読んでると、メソッドインジェクションはコンストラクタの呼べないMonoBehaviorを対象にした機能らしい。なのでPureClassで使う意義は薄いかも。
また、メソッドインジェクションで返り値を
これやったけど動作確認できてない。Zenjectのマニュアル見る感じ、コルーチン用のクラスに移譲させたほうがいい的なアプローチを書いてるので多分怪しい
https://github.com/modesttree/Zenject#frequently-asked-questionsIEnumrator
にすると自動でコルーチンとして動かしてくれるとのこと。便利
public class AsyncProcessor : MonoBehaviour
{
// Purposely left empty
}
public class Foo : IInitializable
{
AsyncProcessor _asyncProcessor;
public Foo(AsyncProcessor asyncProcessor)
{
_asyncProcessor = asyncProcessor;
}
public void Initialize()
{
_asyncProcessor.StartCoroutine(RunAsync());
}
public IEnumerator RunAsync()
{
Debug.Log("Foo started");
yield return new WaitForSeconds(2.0f);
Debug.Log("Foo finished");
}
}
public class TestInstaller : MonoInstaller
{
public override void InstallBindings()
{
Container.Bind<IInitializable>().To<Foo>().AsSingle();
Container.Bind<AsyncProcessor>().FromNewComponentOnNewGameObject().AsSingle();
}
}