4

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.

Chazmus
  • 91
  • 5
  • 1
    I never seen it in use but in the [documetation](https://github.com/modesttree/Zenject) there is an option where you can define the source assembly for your bindings. Check for "AssemblySources" in the Convention Based Binding section – rustyBucketBay May 28 '21 at 15:14
  • Interesting, I hadn't seen the convention based binding stuff. I'll give that a go, thanks! – Chazmus Jun 01 '21 at 09:24
  • let me know if that works, I'll be glad to know :) – rustyBucketBay Jun 01 '21 at 09:59

0 Answers0