Search code examples
c#unity-game-enginezenject

Zenject Resolve object from Project Context with dependencies from Scene Context


I have ProjectContext with some installers for global dependencies. One of the installers:

public class StateMachineInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
         BindStateFactory();
         BindStateMachine();
    }

    private void BindStateMachine() =>
         Container
           .BindInterfacesAndSelfTo<StateMachine>()
           .AsSingle();

    private void BindStateFactory() =>
         Container
           .BindInterfacesTo<StateFactory>()
           .AsSingle();
}

And I also have SceneContext with installer:

public class FruitsInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        Container.BindInterfacesTo<FruitSpawner>().AsSingle();
    }
}

Problem is in StateFactory on state creation.

public class StateFactory : IStateFactory
{
    private readonly IInstantiator _instantiator;

    public StateFactory(IInstantiator instantiator) =>
        _instantiator = instantiator;

    public IExitableState CreateState<TState>() where TState : IExitableState =>
        _instantiator.Instantiate<TState>();
}

In one state I have dependency from SceneContext In this case IFruitSpawner.

public class GameplayState : IState
{
    private readonly IFruitSpawner _fruitSpawner;

    public GameplayState(IFruitSpawner fruitSpawner)
    {
        _fruitSpawner = fruitSpawner;
    }
 
    public void Enter() {// ...}
    public void Exit() {// ...}
}

But I am getting exception: ZenjectException: Unable to resolve 'IFruitSpawner' while building object with type 'GameplayState'. Object graph: GameplayState

How I can resolve dependencies from current SceneContext in StateFactory CreateState<TState>() method?


Solution

  • You can't inject the dependencies declared in SceneContext into the ones declared in ProjectContext. Thus you may solve it in different ways:

    option 1. Bind FruitSpawner in ProjectContext

    option 2. Introduce intermediary service, let's call it SpawnerProvider and bind it in ProjectContext. This service will play the role of service provider for your FruitSpawner (and maybe other spawners as well). Inject it as the dependency into GameplayState. SpawnerProvider should have a property/method that provides the FruitSpawner.

    After the game scene is loaded, you should initialize the properties of this service with FruitSpawner. You should pay attention to the initialization order, to ensure that your GameplayState logic related to the spawner is executed after the SpawnerProvider is initialized.