Stormer
Stormer

Reputation: 946

Extenject - NullReferenceException when second time inject

I'm new at Zenject(Extenject).

My dev environment: Win10, Unity2020, Extenject 9.2.0

Here is my question:

In installer bind the class

Container.Bind<AccountInfo>().AsCached();

Inject it at classA

private AccountInfo accountInfo;             

[Inject]
private void Init(GameSetup _gameSetup, AccountInfo _accountInfo)
{
    this.gameSetup = _gameSetup; 
    this.accountInfo = _accountInfo;
}

accountInfo.address = "xxx'; // works fine

Then inject AccountInfo to classB

private AccountInfo accountInfo;      
        
[Inject]
private void Init(AccountInfo _accountInfo)
{
    this.accountInfo = _accountInfo;
}

accountInfo.address = "xxx'; //NullReferenceException: Object reference not set to an instance of an object

Why accountInfo changed to null? AsCached() dosen't work? Or something worng else?

Help please~~ Thank you!

Here is my code:

Installer enter image description here

"ClassA" inject GameSetup, and create instance, works fine enter image description here

"ClassB" inject GameSetup, Error: null object enter image description here

"ClassB" Creator, I'm trying use container.Instantiate() to create it enter image description here


---update--- gameSetup still Null Object enter image description here

Upvotes: 0

Views: 1363

Answers (2)

Nikolai
Nikolai

Reputation: 1173

There are two cases, when injection will not work properly in your code.

  1. The code, that uses injected object is executed before Init. For example if this code is placed in the construcor.

  2. You create your GameObject/Component in runtime whithout using IInstantiator. While you use Znject you always should use IInstantiator to create objects. To do it you should inject IInstantiator to the object, that creates another objects. IItstantiator is always binded in the container by default, so you don't have to bind it manually. For example:


public class Creator : MonoBehaviour {

    [SerializeField]
    private GameObject _somePrefab;

    private IInstantiator _instantiator;

    [Inject]
    public void Initialize(IInstantiator instantiator) {
        _instantiator = instantiator;
    }

    private void Start() {

        // example of creating components
        var gameObj = new GameObject(); // new empty gameobjects can be created without IInstantiator
        _instantiator.InstantiateComponent<YourComponentClass>(gameObj);

        // example of instantiating prefab
        var prefabInstance = _instantiator.InstantiatePrefab(_somePrefab);
    }

}

Upvotes: 3

rustyBucketBay
rustyBucketBay

Reputation: 4551

Not an expert but I think that passing IInstantiator or the container around is not a good practice. If you need to create injected instances at runtime, then you need a Factory. From the documentation

1.- Best practice with DI is to only reference the container in the composition root "layer"

Note that factories are part of this layer and the container can be referenced there (which is necessary to create objects at runtime).

2.- "When instantiating objects directly, you can either use DiContainer or you can use IInstantiator, which DiContainer inherits from. However, note that injecting the DiContainer is usually a sign of bad practice, since there is almost always a better way to design your code such that you don't need to reference DiContainer directly".

3.- "Once again, best practice with dependency injection is to only reference the DiContainer in the "composition root layer""

Upvotes: 2

Related Questions