ssannandeji / Zenject-2019

Dependency Injection Framework for Unity3D
MIT License
2.53k stars 366 forks source link

Declaring Factory for Object which doesn't have all its dependencies yet #668

Open EmmetOT opened 4 years ago

EmmetOT commented 4 years ago

Hey, I have a specific situation where I have a state machine which I want to be global and scene independent. I want to be able to create new instances of states, states can be scene-dependent (such as a 'combat encounter state') and these scene-dependent states will have dependencies which exist only in that scene (such as 'enemies in the combat encounter'.)

Because I want to create new state objects, I have factories set up for each state class, and contained in a global state factory class which the state machine object has a dependency on. However because this factory class is bound in the start scene, and therefore in a different context than the combat encounter scene, none of the scene-specific bindings are bound correctly when I try to create an instance of the combat encounter state.

Here's a simple example with all the state machine complexity stripped out:

I have an empty MonoBehaviour, ObjectInGameScene, and a class ObjectWithDependency:

public class ObjectWithDependency
{
    private readonly ObjectInGameScene m_object;

    public ObjectWithDependency(ObjectInGameScene objectInGameScene)
    {
        m_object = objectInGameScene;

        Debug.Log("Created a dependency object. Object is null: " + (m_object == null), m_object);
    }

    public class Factory : PlaceholderFactory<ObjectWithDependency>
    {

    }
}

I have a TestFactoryContainer class which just has a dependency on this object's factory:

public class TestFactoryContainer
{
    private readonly ObjectWithDependency.Factory m_factory;

    public TestFactoryContainer(ObjectWithDependency.Factory factory)
    {
        m_factory = factory;
    }

    public void Spawn()
    {
        m_factory.Create();
    }
}

My scenes are set up so that one scene, Start, loads the other Game. Start contains the TestFactoryContainer class whereas the actual ObjectInGameScene object exists in Game. Usually I try binding the factory and factory container in an installer in the start scene, and binding the actual object in the game scene, but unsurprisingly this results in the following error:

ZenjectException: Unable to resolve 'ObjectInGameScene' while building object with type 'ObjectWithDependency'. Object graph:
ObjectWithDependency

because the ObjectWithDependency and the factory classes don't share a Container. I understand that the solution might involve using scene parenting or scene decorator contexts but I've been unable to get either to work. Or maybe this entire approach to using Zenject is flawed.