Hey there!
I’m getting to Zenject and I have questions I can’t find the answer to. I’m starting to understand the whole concept, but it don’t get some stuff related to MonoBehaviours with Zenject.
Basically, the guy that introduced me to Zenject was using a way that the Zenject documentation does not recommend, using mostly field injection. As I went through the documentation, I understood that this is not the best practice, and that it’s better to use Constructor/Method injection instead.
What I was doing until now :
public class MyMonoInstaller : MonoInstaller
{
[SerializeField] private FlowManager _flowManager;
[SerializeField] private UIManager _uiManager;
[SerializeField] private CameraManager _cameraManager;
public override void InstallBindings ()
{
Container.Bind<MyNativeClass>().AsSingle().NonLazy();
Container.Bind<FlowManager>().FromInstance(_flowManager).AsSingle().NonLazy();
Container.Bind<UIManager>().FromInstance(_uiManager).AsSingle().NonLazy();
Container.Bind<CameraManager>().FromInstance(_cameraManager).AsSingle().NonLazy();
}
}
public class GameStarter : MonoBehaviour
{
[Inject] private MyNativeClass _myNativeClass;
[Inject] private FlowManager _flowManager;
[Inject] private UIManager _uiManager;
[Inject] private CameraManager _cameraManager;
private void Start ()
{
_myNativeClass.Init();
_flowManager.Init();
_uiManager.Init();
_cameraManager.Init();
}
}
public class MyNativeClass
{
public void Init ()
{
}
}
And it worked fine. But now that I do it the “good way”, I don’t understand how this code above could even work.
What I do now :
public class MyMonoInstaller : MonoInstaller
{
[SerializeField] private FlowManager _flowManager;
[SerializeField] private UIManager _uiManagerPrefab;
[SerializeField] private CameraManager _cameraManagerPrefab;
public override void InstallBindings ()
{
Container.Bind<MyNativeClass>().AsSingle().NonLazy();
Container.Bind<FlowManager>().FromInstance(_flowManager).AsSingle().NonLazy();
Container.Bind<UIManager>().FromComponentInNewPrefab(_uiManagerPrefab).WithGameObjectName("UIManager").AsSingle().NonLazy();
Container.Bind<CameraManager>().FromComponentInNewPrefab(_cameraManagerPrefab).WithGameObjectName("UIManager").AsSingle().NonLazy();
}
}
public class GameStarter : MonoBehaviour
{
private MyNativeClass _myNativeClass;
private FlowManager _flowManager;
private UIManager _uiManager;
private CameraManager _cameraManager;
[Inject]
public void Construct (MyNativeClass myNativeClass, FlowManager flowManager, UIManager uiManager, CameraManager cameraManager)
{
_myNativeClass = myNativeClass;
_flowManager = flowManager;
_uiManager = uiManager;
_cameraManager = cameraManager;
}
private void Start ()
{
_myNativeClass.Init();
_flowManager.Init();
_uiManager.Init();
_cameraManager.Init();
}
}
public class MyNativeClass
{
public void Init ()
{
}
}
Now I don’t understand why the FlowManager even call Inject on its own class, as it’s already present in the scene and I drag the reference on the MonoInstaller. I understand it does for UIManager and CameraManager as they are instantiated via Zenject, so it calls the “fake constructor”. I’ve seen on the documentation that, when you bind via instance, you must use Container.QueueForInject() so that Zenject can do his work. But it works without doing it, so I’m a bit confused. Also, as it’s already present in the scene, I’m not sure to understand what .NonLazy() does for FlowManager.
Something else I don’t understand is that I have a MonoBehaviour (let’s call it UiThing) class that’s inside a GameWindow, which is inside UIManager. On that UiThing, I have a method injection, and it’s called, and I don’t understand how it can be called, as there is nowhere any binding of UiThing on the Container. Is it somehow because UIManager is binded into the container so it also works for his childs ? Would seem strange, plus, if I do try to Inject that UiThing elsewhere, it doesn’t work, so it’s not binded, which seem logical.
Can anyone help me understand ? :3
Thanks.