My Unity project is split into a Core project and several Modules, in different asmdef assembly definitions. Each module has an assembly reference to Core.
My Core installer looks like:
public class CoreInstaller : MonoInstaller
{
[SerializeField] private GameObject ShipPrefab;
public override void InstallBindings()
{
Container.BindInterfacesTo<GameRunner>().AsSingle();
Container.BindFactory<Ship, Ship.Factory>().FromSubContainerResolve().ByNewPrefabInstaller<ShipInstaller>(ShipPrefab);
}
}
As you can see, I'm using Zenject DI to bind a Ship
to a Ship.Factory
, using the ShipInstaller
to bind dependencies on the ship's subcontainer.
The issue is that ShipInstaller
can bind dependencies that live in the Core
assembly but not in any of the modules.
I have managed to get around this by creating a IShipInstaller
interface which lives in Core
but can be implemented by installers in other modules in order to inject extra dependencies into the Ship object as it is being created. Other Modules have their own installers which can then bind their ship installers to that interface and they all get injected as a list into the ship at runtime.
E.g.
public class OptionalShipInstaller : IShipInstaller
{
public void InstallBindings(DiContainer subContainer)
{
subContainer.BindInterfacesTo<OptionalShipDependency>().AsSingle();
}
}
public class ModuleInstaller: MonoInstaller
{
public override void InstallBindings()
{
Container.BindInterfacesTo<OptionalShipInstaller>().AsSingle();
}
}
public class ShipInstaller : Installer<ShipInstaller>
{
[Inject] private IEnumerable<IShipInstaller> _subContainerInstallers;
public override void InstallBindings()
{
Container.BindInterfacesTo<CoreShipDependency>().AsSingle();
foreach (var subContainerInstaller in _subContainerInstallers)
{
subContainerInstaller.InstallBindings(Container);
}
}
}
This works, but the problem with doing this is that it fails the Zenject validation because during validation I believe it gets the Container.Resolve
method to just return a default value (null or an empty list).
According to the documentation, an installer can run another installer by using the Installer.Install(Container)
for example my OptionalShipInstaller Should look like:
public class OptionalShipInstaller : Installer<OptionalShipInstaller>
{
public override void InstallBindings()
{
Container.BindInterfacesTo<OptionalShipDependency>().AsSingle();
}
}
And the ShipInstaller
should just run the static Install method like so:
public class ShipInstaller : Installer<ShipInstaller>
{
public override void InstallBindings()
{
Container.BindInterfacesTo<CoreShipDependency>().AsSingle();
OptionalShipInstaller.Install(Container);
}
}
However, the OptionalShipInstaller
is not visible to the ShipInstaller
as it lives in a separate assembly that is not referenced in Core
- Modules depend on Core, not the other way around!
So basically, is there a way of me perhaps attaching another installer to the ships factory after it has been bound? Or any other ways I could solve this issue would be massively appreciated.